背景

本文是《Java 后端从小白到大神》修仙系列之框架学习,Java框架之Spring框架第一篇。本篇文章主要聊Java框架,那么必然从Spring框架开始,可以说Spring框架是Java企业级开发的基石,我们现在开始吧。

文章概览

  1. 核心容器(Core Container)
  2. 面向切面编程 (AOP)
  3. 数据访问与事务管理(Data Access & Tx)

Spring框架

1. 核心容器(Core Container)

下图是Spring框架的整体架构,从架构图我们可以看出来core container是Spring的基石,即常说的IOC容器。在此基础上才有AOP,DATA和WEB的繁荣,所有其他的Spring组件都是在容器上构建出来的。Spring最核心的3个jar包是bean、context、core。bean是spring的基石,一切皆为bean,context维护了应用上下文,若bean是演员,context则为舞台,core为道具。

1.1 架构图

graph TB
    subgraph "SPRING FRAMEWORK RUNTIME"
        subgraph " "
            direction TB
            subgraph "Data Access/Integration"
                A1[JDBC] --> A2[ORM]
                A3[OXM] --> A4[JMS]
                A5[Transactions]
            end

            subgraph "Web (MVC/Remoting)"
                B1[Web] --> B2[Servlet]
                B3[Portlet] --> B4[Struts]
            end
        end

        subgraph "  "
            direction TB
            subgraph "AOP"
                C1[AOP]
            end

            subgraph "Aspects"
                D1[Aspects]
            end

            subgraph "Instrumentation"
                E1[Instrumentation]
            end
        end

        subgraph "   "
            subgraph "Core Container"
                F1[Beans] 
                F2[Core]
                F3[Context]
                F4[Expression Language]
            end
        end

        subgraph "Test"
            G1[Test]
        end
        
    end

1.2 什么是 Spring 容器?

Spring容器就是一个管理对象(Bean)生命周期和依赖关系的容器。
简单说,它负责:

  • 创建对象(Bean实例化)
  • 维护对象之间的依赖关系(依赖注入)
  • 管理对象的生命周期(初始化、销毁)
  • 提供容器级的扩展(AOP、事件发布、资源加载等)

从本质上讲,Spring容器就是一个高级的工厂模式实现,管理了对象的创建、组装、生命周期,同时提供了扩展点。一句话总结:Spring容器 = 一个高级的对象工厂+生命周期管理器+扩展平台

1.3 Spring 容器的组成

Spring的容器,本质是对BeanFactoryApplicationContext两个大接口体系的不断扩展和实现。

(1)BeanFactory 系列(基础容器接口)

BeanFactory 是最底层、最基本的Spring容器接口,负责管理Bean的生命周期,DefaultListableBeanFactory 是大部分情况下真正承载所有Bean定义和实例管理的容器核心。

BeanFactory (基础工厂)
│
├── HierarchicalBeanFactory(分层父子容器)
│
├── ListableBeanFactory(可以列出Bean的名字/类型)
│
└── AutowireCapableBeanFactory(支持自动注入和Bean生命周期回调)
      │
      └── ConfigurableBeanFactory(可配置BeanFactory,比如添加后置处理器、作用域、值解析器)
             │
             └── DefaultListableBeanFactory(最常用的Bean工厂实现类)

(2)ApplicationContext 系列(高级容器接口)

ApplicationContext 是对 BeanFactory 的功能增强,提供了:

  • 国际化(MessageSource)
  • 资源加载(ResourceLoader)
  • 应用事件发布(ApplicationEventPublisher)
  • 容器环境管理(EnvironmentCapable)

AbstractApplicationContext 定义了容器启动、刷新、关闭的基本流程(如refresh()方法)。GenericApplicationContext 是纯净、轻量的手动控制型容。AnnotationConfigApplicationContext注解驱动的标准容器,常用于现代Spring应用。ClassPathXmlApplicationContextXML配置传统容器。WebApplicationContextWeb应用专用容器,嵌套了Servlet环境的支持。

结构如下:

ApplicationContext (应用上下文,扩展了BeanFactory)
│
├── EnvironmentCapable (管理环境属性)
│
├── ResourceLoader (加载资源,如classpath:、file:、url)
│
├── ApplicationEventPublisher (事件发布机制)
│
├── MessageSource (国际化消息源)
│
└── ConfigurableApplicationContext(可配置的ApplicationContext,提供refresh/close)
        │
        └── AbstractApplicationContext(ApplicationContext抽象基础实现类,实现了容器启动、关闭、刷新流程)
               │
               ├── GenericApplicationContext(通用容器,可手动注册Bean定义)
               │
               ├── AnnotationConfigApplicationContext(基于注解驱动的容器,常用于Spring Boot)
               │
               ├── ClassPathXmlApplicationContext(基于XML配置的容器,传统用法)
               │
               └── WebApplicationContext(用于Web环境,比如Spring MVC DispatcherServlet用的)

(3)特别关键的几个容器实现类

容器实现类 说明
DefaultListableBeanFactory 真正存储和管理所有Bean定义和实例的底层工厂,几乎所有场景都依赖它
AbstractApplicationContext 定义了容器的生命周期(如refresh/close),模板方法模式
GenericApplicationContext 轻量、灵活,可以自己注册BeanDefinition,不绑定具体配置形式
AnnotationConfigApplicationContext 基于注解(@Configuration,@ComponentScan)启动容器,Spring Boot默认使用它
ClassPathXmlApplicationContext 通过加载XML配置文件启动容器(老项目常见)
WebApplicationContext Web环境容器,支持ServletContext,Spring MVC使用它

一句话总结:Spring容器= 基础的BeanFactory(负责Bean生命周期) + 高级的ApplicationContext(负责环境、事件、国际化),实际运行时,容器由DefaultListableBeanFactory负责底层数据存储,AbstractApplicationContext负责顶层调度流程,常用的有注解版(AnnotationConfigApplicationContext)、XML版(ClassPathXmlApplicationContext)、Web版(WebApplicationContext)。

1.4 refresh() 方法流程详解

refresh() 是 Spring 容器最重要的一个方法,它负责:

  • 准备容器
  • 加载Bean定义
  • 实例化Bean
  • 完成初始化

来,详细步骤(官方源码位于 AbstractApplicationContext 中):

(1) refresh() 方法核心步骤流程图

refresh()
│
├── prepareRefresh() 
│   └── 容器准备阶段(初始化环境属性、设置启动时间、校验配置)
│
├── obtainFreshBeanFactory()
│   └── 获取新的 BeanFactory(加载配置,创建/刷新BeanFactory,并解析BeanDefinition)
│   └── 真正解析 @Bean、@Component、@Service 注解,产生 BeanDefinition 的地方是在obtainFreshBeanFactory() ➔ refreshBeanFactory() ➔ loadBeanDefinitions()
│
├── prepareBeanFactory(beanFactory)
│   └── 配置BeanFactory基本属性(ClassLoader、后置处理器等)
│
├── postProcessBeanFactory(beanFactory)
│   └── 容器自定义扩展点(留给子类修改BeanFactory,如Spring Boot里做了一堆事情)
│   └── post前缀 = 后置的、后续阶段,意思是在BeanFactory准备好之后,Bean定义已经加载完毕了,但还没正式创建Bean对象前,给开发者修改bean定义的机会
│
├── invokeBeanFactoryPostProcessors(beanFactory)
│   └── 调用BeanFactoryPostProcessor,比如修改BeanDefinition(超重要)
│   └── PostProcessor后置处理器,在 BeanFactory 初始化后,做一些加工处理,是 “执行处理的对象/角色”
│
├── registerBeanPostProcessors(beanFactory)
│   └── 注册BeanPostProcessor,比如AOP、事务等功能的核心
│
├── initMessageSource()
│   └── 国际化消息源初始化
│
├── initApplicationEventMulticaster()
│   └── 初始化事件发布器(ApplicationEventPublisher)
│
├── onRefresh()
│   └── 留给子类扩展(比如SpringMVC初始化DispatcherServlet)
│
├── registerListeners()
│   └── 注册事件监听器
│
├── finishBeanFactoryInitialization(beanFactory)
│   └── 真正实例化非懒加载的单例Bean
│
└── finishRefresh()
    └── 通知监听器,刷新完成,整个容器可用了,触发生命周期回调(如SmartInitializingSingleton)

(2) refresh() 方法核心步骤流程图

继续从 refresh() 每一步内部,特别是重要的步骤源码分析,比如:

  • invokeBeanFactoryPostProcessors
  • registerBeanPostProcessors
  • finishBeanFactoryInitialization

invokeBeanFactoryPostProcessors 内部发生了什么?

这个步骤非常非常重要!

主要完成了:

  • 处理所有 BeanDefinitionRegistryPostProcessor(用于动态注册新的Bean)
  • 处理所有 BeanFactoryPostProcessor(用于修改现有Bean定义)

源码(简化版逻辑)大致是:

1
2
3
4
5
6
7
8
9
// Step1:先调用 BeanDefinitionRegistryPostProcessor.postProcessBeanDefinitionRegistry()
for (BeanDefinitionRegistryPostProcessor registryProcessor : registryProcessors) {
    registryProcessor.postProcessBeanDefinitionRegistry(registry);
}

// Step2:再调用所有 BeanFactoryPostProcessor.postProcessBeanFactory()
for (BeanFactoryPostProcessor factoryProcessor : factoryProcessors) {
    factoryProcessor.postProcessBeanFactory(beanFactory);
}

特别提示:Spring Boot的自动配置原理,就是在这个阶段动态注册Bean定义(比如通过@ConditionalOnMissingBean)。MyBatis、Spring Cloud 等框架,也是这里通过扫描/动态添加Bean的。 所以,invokeBeanFactoryPostProcessors动态注册和修改Bean定义的关键步骤!

registerBeanPostProcessors 内部发生了什么?

这是注册BeanPostProcessor的阶段!

BeanPostProcessor是干嘛的?

  • Bean实例化前后 插入自定义逻辑,比如AOP代理、事务增强、@Autowired注入处理等等。

流程是这样的(简化):

1
2
3
4
List<BeanPostProcessor> postProcessors = findBeanPostProcessors();
for (BeanPostProcessor processor : postProcessors) {
    beanFactory.addBeanPostProcessor(processor);
}

特别注意:BeanPostProcessor自己也是个Bean,但要提早实例化,因为后续需要依赖它们处理普通Bean!Spring AOP的代理创建,就是靠BeanPostProcessor(比如 ProxyBeanPostProcessor)在这里注册的。

finishBeanFactoryInitialization 内部发生了什么?

终于开始实例化真正的Bean了!

这里做了两件大事:

  1. 初始化 ConversionServiceembeddedValueResolver 等环境工具
  2. 实例化所有非懒加载单例Bean

最关键的是这句代码:

1
beanFactory.preInstantiateSingletons();

preInstantiateSingletons() 做的事情是:

  • 遍历所有BeanDefinition
  • 对于单例非懒加载的Bean
    • 调用 getBean(beanName)
    • 创建Bean(如果还没实例化)

(2) Bean生命周期时序图

refresh()
│
├── invokeBeanFactoryPostProcessors
│      └── 处理 BeanDefinitionRegistryPostProcessor
│      └── 处理 BeanFactoryPostProcessor
│
├── registerBeanPostProcessors
│      └── 注册 BeanPostProcessor(AOP,事务,@Autowired处理器)
│
├── finishBeanFactoryInitialization
│      └── preInstantiateSingletons()
│          ├── 实例化Bean(调用构造器)
│          ├── populateBean(填充属性,@Autowired)
│          ├── 调用 BeanPostProcessor.postProcessBeforeInitialization()
│          ├── 调用 @PostConstruct、InitializingBean.afterPropertiesSet()
│          ├── 调用 BeanPostProcessor.postProcessAfterInitialization()
│
└── finishRefresh()
       └── 发布 ContextRefreshedEvent
       └── 调用 SmartInitializingSingleton.afterSingletonsInstantiated()

1.5 依赖注入(DI)与控制反转(IoC)原理

  • 控制反转(IoC)概念:将对象创建与依赖管理的控制权从应用程序代码中“反转”到容器中。应用不再主动new依赖对象,而是由容器负责组装所需组件。
  • 依赖注入(DI)概念:IoC 的具体实现方式之一,通过将所需依赖(例如 service、repository)注入到目标对象中,减少硬编码耦合。

1.6 Spring 中如何实现 IoC/DI

Spring 容器(BeanFactory/ApplicationContext)负责:

  • 加载 Bean 定义:读取 XML 配置文件、扫描带注解的类、或解析 @Configuration@Bean 注解。
  • 管理 Bean 生命周期:实例化、依赖注入、初始化回调、销毁回调等流程统一管理。
  • 注入依赖:根据类型(byType)、名称(byName)或构造函数参数,将所需 Bean 自动注入。

1.7 三种 Bean 定义方式与原理

(1)XML 配置

  • applicationContext.xml 中以 <bean id="userService" class="com.example.UserService" 标签定义。

  • Spring 使用 JAXP XML 解析器读取元素,将 class 属性映射为对应 Java Class,通过反射实例化并注入属性或构造函数。

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    
    <!-- applicationContext.xml -->
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
                               http://www.springframework.org/schema/beans/spring-beans.xsd">
        <bean id="userRepository" class="com.example.UserRepository"/>
        <bean id="userService" class="com.example.UserService">
            <constructor-arg ref="userRepository"/>
        </bean>
    </beans>
    

(2)Java 注解

  • 通过 @Configuration 类和 @Bean 方法在 Java 代码中直接定义 Bean。

  • Spring 在启动时扫描带 @Configuration 的类,解析 @Bean 方法,使用反射调用并管理方法返回的对象。

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    
    @Configuration
    public class AppConfig {
        @Bean
        public UserRepository userRepository() {
            return new UserRepository();
        }
    
        @Bean
        public UserService userService(UserRepository repo) {
            return new UserService(repo);
        }
    }
    

(3)类路径扫描(Component Scan)

  • 在主配置上使用 @ComponentScan 指定包路径,Spring 扫描带有 @Component@Service@Repository@Controller 等注解的类。

  • Spring 使用 ASM 或反射读取 Class 文件中的注解元数据,将这些类注册为 BeanDefinition,再实例化注入。

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    
    @Configuration
    @ComponentScan("com.example")
    public class AppConfig {}
    
    @Service
    public class UserService {
        @Autowired
        private UserRepository repo;
        // ...
    }
    
    @Repository
    public class UserRepository {
        // ...
    }
    

为什么 Java 能支持这三种方式?

  • 反射机制:Java 提供 Class.forName()ConstructorMethod 等反射 API,Spring 可以动态加载并实例化任意类。
  • 注解处理:Java 注解会在编译时或运行时保留元数据,Spring 能借助 AnnotationMetadata 与 ASM 库读取并处理。
  • 类加载与资源访问:Spring 能通过 ResourceLoader 访问类路径下的 XML、Properties、Class 文件,实现统一配置加载。

1.8 Bean 生命周期与作用域(Scopes)

(1)Bean 作用域
  • singleton(单例,默认):整个 Spring IoC 容器中仅创建一个共享 Bean 实例。适合无状态、线程安全的对象。
  • prototype(原型):每次通过容器获取 Bean 时都创建一个新实例;容器不管理销毁生命周期。适合有状态对象。
  • request(Web 应用):在一次 HTTP 请求内有效,每次请求都会新建一个 Bean,请求结束后销毁。
  • session(Web 应用):在一个 HTTP 会话内有效,每个会话一个 Bean,Session 过期或失效后销毁。
  • application(Web 应用):与 ServletContext 作用域相同,整个 web 应用生命周期内共享一个 Bean。

示例:声明不同作用域 Bean

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
@Component
@Scope("prototype")
public class ShoppingCart {
    private List<Itemitems = new ArrayList<();
    public void add(Item i) { items.add(i); }
}

@Component
@Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
public class RequestData {
    private String id = UUID.randomUUID().toString();
    public String getId() { return id; }
}
(2)Bean 生命周期回调
  • 实例化阶段:Spring 通过反射调用无参构造器创建 Bean。
  • 依赖注入阶段:填充属性、调用构造函数注入。
  • Aware 回调:若实现 BeanNameAwareBeanFactoryAware 等接口,Spring 会注入对应容器引用。
  • BeanPostProcessor 前置处理:调用 postProcessBeforeInitialization。常用于实现自定义注解逻辑。
  • 初始化回调
    • 实现 InitializingBeanafterPropertiesSet() 方法
    • 或使用 @PostConstruct 注解标记方法
    • 或通过 @Bean(initMethod) 指定
  • BeanPostProcessor 后置处理:调用 postProcessAfterInitialization
  • 销毁回调(仅 singleton):
    • 实现 DisposableBeandestroy() 方法
    • 或使用 @PreDestroy 注解
    • 或通过 @Bean(destroyMethod) 指定

示例:完整生命周期回调

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
@Component
public class LifeCycleBean implements InitializingBean, DisposableBean {
    @PostConstruct
    public void postConstruct() { System.out.println("@PostConstruct"); }
    @Override
    public void afterPropertiesSet() { System.out.println("afterPropertiesSet"); }
    @Bean(initMethod="customInit", destroyMethod="customDestroy")
    public void customInit() { System.out.println("custom init"); }
    @PreDestroy
    public void preDestroy() { System.out.println("@PreDestroy"); }
    @Override
    public void destroy() { System.out.println("DisposableBean destroy"); }
    public void customDestroy() { System.out.println("custom destroy"); }
}

示例:创建两种上下文并加载 Bean

1
2
3
4
5
6
7
8
// BeanFactory 示例
Resource res = new ClassPathResource("beans.xml");
BeanFactory factory = new XmlBeanFactory(res);
MyService svc1 = factory.getBean(MyService.class); // 触发加载

// ApplicationContext 示例
ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
MyService svc2 = ctx.getBean(MyService.class); // Bean 已预实例化

1.9 手写一个Mini版Spring容器

V1.0版(最小可用) 版本,先实现这几个基本功能:

  • 注册Bean定义(BeanDefinition)
  • 创建Bean实例
  • 通过getBean拿到实例
  • 有一个类似refresh()的方法初始化容器
1. 定义 BeanDefinition 类
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
// 保存Bean的元信息,比如class类型
public class BeanDefinition {
    private Class<?> beanClass;

    public BeanDefinition(Class<?> beanClass) {
        this.beanClass = beanClass;
    }

    public Class<?> getBeanClass() {
        return beanClass;
    }
}
2. 定义 MiniApplicationContext 容器
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
import java.util.HashMap;
import java.util.Map;

public class MiniApplicationContext {

    // 保存注册的Bean定义
    private Map<String, BeanDefinition> beanDefinitionMap = new HashMap<>();

    // 保存创建好的单例Bean实例
    private Map<String, Object> singletonBeans = new HashMap<>();

    // 注册Bean定义
    public void registerBeanDefinition(String name, Class<?> beanClass) {
        beanDefinitionMap.put(name, new BeanDefinition(beanClass));
    }

    // 初始化(类似refresh)
    public void refresh() {
        // 遍历bean定义,实例化bean
        for (Map.Entry<String, BeanDefinition> entry : beanDefinitionMap.entrySet()) {
            String beanName = entry.getKey();
            BeanDefinition definition = entry.getValue();
            try {
                Object bean = definition.getBeanClass().getDeclaredConstructor().newInstance();
                singletonBeans.put(beanName, bean);
            } catch (Exception e) {
                throw new RuntimeException("Failed to create bean: " + beanName, e);
            }
        }
    }

    // 获取Bean
    public Object getBean(String name) {
        return singletonBeans.get(name);
    }
}
3. 测试用例:UserService 类
1
2
3
4
5
public class UserService {
    public void sayHello() {
        System.out.println("Hello, Mini Spring!");
    }
}
4. 测试启动
1
2
3
4
5
6
7
8
9
public class TestMiniSpring {
    public static void main(String[] args) {
        MiniApplicationContext context = new MiniApplicationContext();
        context.registerBeanDefinition("userService", UserService.class);
        context.refresh();
        UserService userService = (UserService) context.getBean("userService");
        userService.sayHello(); // 输出: Hello, Mini Spring!
    }
}

V2.0版,在V1的基础上实现依赖注入:

  • 注册 Bean
  • 实例化 Bean
  • refresh 初始化
  • getBean 取出
  • Setter方法自动依赖注入
1. 改进版 MiniApplicationContext
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

public class MiniApplicationContext {

    private Map<String, BeanDefinition> beanDefinitionMap = new HashMap<>();
    private Map<String, Object> singletonBeans = new HashMap<>();

    public void registerBeanDefinition(String name, Class<?> beanClass) {
        beanDefinitionMap.put(name, new BeanDefinition(beanClass));
    }

    public void refresh() {
        // 第一步:实例化所有Bean
        for (Map.Entry<String, BeanDefinition> entry : beanDefinitionMap.entrySet()) {
            String beanName = entry.getKey();
            BeanDefinition definition = entry.getValue();
            try {
                Object bean = definition.getBeanClass().getDeclaredConstructor().newInstance();
                singletonBeans.put(beanName, bean);
            } catch (Exception e) {
                throw new RuntimeException("Failed to create bean: " + beanName, e);
            }
        }

        // 第二步:依赖注入(setter注入)
        for (Map.Entry<String, Object> entry : singletonBeans.entrySet()) {
            Object bean = entry.getValue();
            injectDependencies(bean);
        }
    }

    private void injectDependencies(Object bean) {
        Method[] methods = bean.getClass().getMethods();
        for (Method method : methods) {
            // 找到所有setter方法
            if (isSetter(method)) {
                Class<?> paramType = method.getParameterTypes()[0];
                // 根据类型找到容器中已有的Bean
                Object dependency = findBeanByType(paramType);
                if (dependency != null) {
                    try {
                        method.invoke(bean, dependency);
                    } catch (Exception e) {
                        throw new RuntimeException("Failed to inject dependency: " + method.getName(), e);
                    }
                }
            }
        }
    }

    private boolean isSetter(Method method) {
        return method.getName().startsWith("set")
                && method.getParameterCount() == 1;
    }

    private Object findBeanByType(Class<?> type) {
        for (Object bean : singletonBeans.values()) {
            if (type.isAssignableFrom(bean.getClass())) {
                return bean;
            }
        }
        return null;
    }

    public Object getBean(String name) {
        return singletonBeans.get(name);
    }
}
2. 测试用例:UserService 类
1
2
3
4
5
public class UserService {
    public void sayHello() {
        System.out.println("Hello, Mini Spring!");
    }
}
3. 测试用例:OrderService 类
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
public class OrderService {
    private UserService userService;

    public void setUserService(UserService userService) {
        this.userService = userService;
    }

    public void placeOrder() {
        System.out.println("Placing order...");
        userService.sayHello();
    }
}
4. 测试启动
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
public class TestMiniSpring {
    public static void main(String[] args) {
        MiniApplicationContext context = new MiniApplicationContext();
        context.registerBeanDefinition("userService", UserService.class);
        context.registerBeanDefinition("orderService", OrderService.class);
        context.refresh();
        
        OrderService orderService = (OrderService) context.getBean("orderService");
        orderService.placeOrder();
    }
}

V3.0版,在V2的基础上实现以下功能:

  • 支持构造器注入(Constructor Injection)
  • 支持自定义注解 @MiniAutowired,自动注入
  • 支持生命周期回调 afterPropertiesSet
  • 支持单例/多例(Scope管理)
  • 支持懒加载(Lazy Init)
1. 自定义注解 @MiniAutowired
1
2
3
4
5
6
import java.lang.annotation.*;

@Target({ElementType.FIELD, ElementType.CONSTRUCTOR})
@Retention(RetentionPolicy.RUNTIME)
public @interface MiniAutowired {
}
2. BeanDefinition扩展
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class BeanDefinition {
    private Class<?> beanClass;
    private String scope = "singleton"; // 默认是单例
    private boolean lazyInit = false;   // 默认不是懒加载

    public BeanDefinition(Class<?> beanClass) {
        this.beanClass = beanClass;
    }

    // getter、setter 省略
    public Class<?> getBeanClass() {
        return beanClass;
    }

    public String getScope() {
        return scope;
    }

    public void setScope(String scope) {
        this.scope = scope;
    }

    public boolean isLazyInit() {
        return lazyInit;
    }

    public void setLazyInit(boolean lazyInit) {
        this.lazyInit = lazyInit;
    }
}
3. 生命周期接口(仿 Spring 的 InitializingBean)
1
2
3
public interface MiniInitializingBean {
    void afterPropertiesSet();
}
4. 核心改造 MiniApplicationContext
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
import java.lang.reflect.*;
import java.util.*;

public class MiniApplicationContext {

    private Map<String, BeanDefinition> beanDefinitionMap = new HashMap<>();
    private Map<String, Object> singletonBeans = new HashMap<>();

    public void registerBeanDefinition(String name, Class<?> beanClass) {
        BeanDefinition definition = new BeanDefinition(beanClass);
        beanDefinitionMap.put(name, definition);
    }

    public void refresh() {
        // 提前实例化非懒加载且单例的Bean
        for (Map.Entry<String, BeanDefinition> entry : beanDefinitionMap.entrySet()) {
            String beanName = entry.getKey();
            BeanDefinition definition = entry.getValue();
            if (!definition.isLazyInit() && "singleton".equals(definition.getScope())) {
                createBean(beanName, definition);
            }
        }
    }

    private Object createBean(String beanName, BeanDefinition definition) {
        if ("singleton".equals(definition.getScope()) && singletonBeans.containsKey(beanName)) {
            return singletonBeans.get(beanName);
        }

        try {
            Class<?> clazz = definition.getBeanClass();
            Object instance;

            // 优先找有 @MiniAutowired 注解的构造器
            Constructor<?>[] constructors = clazz.getDeclaredConstructors();
            Constructor<?> autowiredConstructor = null;
            for (Constructor<?> constructor : constructors) {
                if (constructor.isAnnotationPresent(MiniAutowired.class)) {
                    autowiredConstructor = constructor;
                    break;
                }
            }

            if (autowiredConstructor != null) {
                // 构造器注入
                Class<?>[] paramTypes = autowiredConstructor.getParameterTypes();
                Object[] params = new Object[paramTypes.length];
                for (int i = 0; i < paramTypes.length; i++) {
                    params[i] = findBeanByType(paramTypes[i]);
                }
                instance = autowiredConstructor.newInstance(params);
            } else {
                // 默认无参构造
                instance = clazz.getDeclaredConstructor().newInstance();
            }

            // 字段注入
            for (Field field : clazz.getDeclaredFields()) {
                if (field.isAnnotationPresent(MiniAutowired.class)) {
                    field.setAccessible(true);
                    Object dependency = findBeanByType(field.getType());
                    field.set(instance, dependency);
                }
            }

            // 调用afterPropertiesSet方法
            if (instance instanceof MiniInitializingBean) {
                ((MiniInitializingBean) instance).afterPropertiesSet();
            }

            // 单例池保存
            if ("singleton".equals(definition.getScope())) {
                singletonBeans.put(beanName, instance);
            }

            return instance;

        } catch (Exception e) {
            throw new RuntimeException("Failed to create bean: " + beanName, e);
        }
    }

    private Object findBeanByType(Class<?> type) {
        for (Map.Entry<String, BeanDefinition> entry : beanDefinitionMap.entrySet()) {
            BeanDefinition definition = entry.getValue();
            Object bean;
            if ("singleton".equals(definition.getScope())) {
                bean = singletonBeans.get(entry.getKey());
                if (bean == null) {
                    bean = createBean(entry.getKey(), definition);
                }
            } else {
                bean = createBean(entry.getKey(), definition);
            }
            if (type.isAssignableFrom(bean.getClass())) {
                return bean;
            }
        }
        return null;
    }

    public Object getBean(String name) {
        BeanDefinition definition = beanDefinitionMap.get(name);
        if (definition == null) {
            throw new RuntimeException("No bean named " + name);
        }
        if ("singleton".equals(definition.getScope())) {
            Object bean = singletonBeans.get(name);
            if (bean == null) {
                bean = createBean(name, definition);
            }
            return bean;
        } else {
            return createBean(name, definition);
        }
    }

    // 支持给BeanDefinition设定scope
    public void setScope(String name, String scope) {
        BeanDefinition definition = beanDefinitionMap.get(name);
        if (definition != null) {
            definition.setScope(scope);
        }
    }

    // 支持给BeanDefinition设定懒加载
    public void setLazyInit(String name, boolean lazy) {
        BeanDefinition definition = beanDefinitionMap.get(name);
        if (definition != null) {
            definition.setLazyInit(lazy);
        }
    }
}
6. 测试案例:UserService类
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
public class UserService implements MiniInitializingBean {
    public void sayHello() {
        System.out.println("Hello from UserService");
    }

    @Override
    public void afterPropertiesSet() {
        System.out.println("UserService afterPropertiesSet called!");
    }
}
7. OrderService(构造器注入)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
public class OrderService {

    private final UserService userService;

    @MiniAutowired
    public OrderService(UserService userService) {
        this.userService = userService;
    }

    public void placeOrder() {
        System.out.println("Order placed!");
        userService.sayHello();
    }
}
9. 测试启动
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
public class TestMiniSpring {
    public static void main(String[] args) {
        MiniApplicationContext context = new MiniApplicationContext();

        context.registerBeanDefinition("userService", UserService.class);
        context.registerBeanDefinition("orderService", OrderService.class);

        // 设置懒加载示范(比如OrderService懒加载)
        context.setLazyInit("orderService", true);

        context.refresh();

        System.out.println("---拿到OrderService---");
        OrderService orderService = (OrderService) context.getBean("orderService");
        orderService.placeOrder();
    }
}

V4.0版,实现组件扫描功能:

  • 组件扫描(Component Scan)
1.组件扫描(Component Scan)
1
2
3
4
5
6
import java.lang.annotation.*;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MiniComponent {
}
2.在MiniApplicationContext中增加扫描指定包功能
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
import java.io.File;
import java.net.URL;
import java.util.*;

public class MiniApplicationContext {

    private Map<String, BeanDefinition> beanDefinitionMap = new HashMap<>();
    private Map<String, Object> singletonBeans = new HashMap<>();

    public MiniApplicationContext(String basePackage) {
        scan(basePackage);
        refresh();
    }

    // 之前已有的 registerBeanDefinition(),refresh(),createBean()等保持不变

    private void scan(String basePackage) {
        String path = basePackage.replace('.', '/');
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        URL resource = classLoader.getResource(path);
        if (resource == null) {
            throw new RuntimeException("No resource found for package " + basePackage);
        }

        File baseDir = new File(resource.getFile());
        for (File file : Objects.requireNonNull(baseDir.listFiles())) {
            if (file.getName().endsWith(".class")) {
                String className = basePackage + '.' + file.getName().replace(".class", "");
                try {
                    Class<?> clazz = Class.forName(className);
                    if (clazz.isAnnotationPresent(MiniComponent.class)) {
                        String beanName = Introspector.decapitalize(clazz.getSimpleName());
                        registerBeanDefinition(beanName, clazz);
                    }
                } catch (ClassNotFoundException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }
}
3.定义一个被扫描的类
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
@MiniComponent
public class UserService implements MiniInitializingBean {
    public void sayHello() {
        System.out.println("UserService says: Hello!");
    }

    @Override
    public void afterPropertiesSet() {
        System.out.println("UserService initialized via afterPropertiesSet");
    }
}
4.测试启动
1
2
3
4
5
6
7
public class TestScan {
    public static void main(String[] args) {
        MiniApplicationContext context = new MiniApplicationContext("com.example.demo");
        UserService userService = (UserService) context.getBean("userService");
        userService.sayHello();
    }
}

V5.0版,实现事件发布监听机制(Mini版 ApplicationEvent / ApplicationListener)功能:

  • 定义事件(MiniApplicationEvent):所有事件都继承它。
  • 定义监听器(MiniApplicationListener):所有监听器都实现它。
  • 定义事件发布器(MiniApplicationEventPublisher):容器在需要时负责发布事件。
  • 在容器启动时,扫描所有监听器,并保存下来。
  • 发布事件时,通知对应监听器。
1. 事件基类:MiniApplicationEvent
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
public class MiniApplicationEvent {
    private final Object source;

    public MiniApplicationEvent(Object source) {
        this.source = source;
    }

    public Object getSource() {
        return source;
    }
}
2. 监听器接口:MiniApplicationListener
1
2
3
public interface MiniApplicationListener<E extends MiniApplicationEvent> {
    void onApplicationEvent(E event);
}
3. 事件发布器接口:MiniApplicationEventPublisher
1
2
3
public interface MiniApplicationEventPublisher {
    void publishEvent(MiniApplicationEvent event);
}
4. 在容器(MiniApplicationContext)中集成
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
import java.util.ArrayList;
import java.util.List;

public class MiniApplicationContext implements MiniApplicationEventPublisher {
    private Map<String, BeanDefinition> beanDefinitionMap = new HashMap<>();
    private Map<String, Object> singletonBeans = new HashMap<>();
    private List<MiniApplicationListener<?>> applicationListeners = new ArrayList<>();

    public MiniApplicationContext(String basePackage) {
        scan(basePackage);
        refresh();
    }

    private void scan(String basePackage) {
        // 略(见上文)
    }

    private void refresh() {
        for (String beanName : beanDefinitionMap.keySet()) {
            BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
            if (!beanDefinition.isLazyInit() && beanDefinition.isSingleton()) {
                getBean(beanName);
            }
        }

        // 在 refresh 后,收集监听器
        for (Object bean : singletonBeans.values()) {
            if (bean instanceof MiniApplicationListener) {
                applicationListeners.add((MiniApplicationListener<?>) bean);
            }
        }

        // 发布容器启动完成事件
        publishEvent(new MiniContextRefreshedEvent(this));
    }

    public Object getBean(String beanName) {
        // 之前已有代码
        return singletonBeans.get(beanName);
    }

    @Override
    public void publishEvent(MiniApplicationEvent event) {
        for (MiniApplicationListener<?> listener : applicationListeners) {
            invokeListener(listener, event);
        }
    }

    @SuppressWarnings({"unchecked", "rawtypes"})
    private void invokeListener(MiniApplicationListener listener, MiniApplicationEvent event) {
        listener.onApplicationEvent(event);
    }
}
5. 定义一个具体事件:MiniContextRefreshedEvent
1
2
3
4
5
public class MiniContextRefreshedEvent extends MiniApplicationEvent {
    public MiniContextRefreshedEvent(Object source) {
        super(source);
    }
}
6. 定义一个监听器示例
1
2
3
4
5
6
7
@MiniComponent
public class ContextRefreshListener implements MiniApplicationListener<MiniContextRefreshedEvent> {
    @Override
    public void onApplicationEvent(MiniContextRefreshedEvent event) {
        System.out.println("🎉 容器刷新完成!收到 MiniContextRefreshedEvent!");
    }
}
7. 手动自定义个事件
1
2
3
4
5
public class MiniCustomEvent extends MiniApplicationEvent {
    public MiniCustomEvent(Object source) {
        super(source);
    }
}
8. 测试启动
1
2
3
4
5
6
7
8
9
public class TestEvent {
    public static void main(String[] args) {
        MiniApplicationContext context = new MiniApplicationContext("com.example.demo");
        // 自动打印:"容器刷新完成!收到 MiniContextRefreshedEvent!"

        // 手动发布一个事件
        context.publishEvent(new MiniCustomEvent(context));
    }
}

V6.0版本,实现面向切面编程(AOP)功能:

  • 定义 AOP 核心注解(@MiniAspect)
  • 定义方法拦截器接口(MiniMethodInterceptor)
  • 实现代理工厂(MiniProxyFactory)(支持 JDK + CGLIB 两种)
  • 容器中集成 AOP 支持(wrapIfNeeded)
  • 定义业务Bean测试(带不带接口都行)
  • 测试:接口类+普通类代理
1. 定义 AOP 核心注解
1
2
3
4
5
6
import java.lang.annotation.*;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MiniAspect {
}
2. 定义方法拦截器接口
1
2
3
4
5
import java.lang.reflect.Method;

public interface MiniMethodInterceptor {
    Object invoke(Method method, Object[] args, Object target) throws Throwable;
}
3. 实现代理工厂(JDK + CGLIB)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

public class MiniProxyFactory {

    public static Object createProxy(Object target, MiniMethodInterceptor interceptor) {
        Class<?> targetClass = target.getClass();

        if (targetClass.getInterfaces().length > 0) {
            // 使用 JDK 动态代理
            return Proxy.newProxyInstance(
                    targetClass.getClassLoader(),
                    targetClass.getInterfaces(),
                    new InvocationHandler() {
                        @Override
                        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                            return interceptor.invoke(method, args, target);
                        }
                    }
            );
        } else {
            // 使用 CGLIB 动态代理
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(targetClass);
            enhancer.setCallback(new MethodInterceptor() {
                @Override
                public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                    return interceptor.invoke(method, args, target);
                }
            });
            return enhancer.create();
        }
    }
}
4. 容器中集成(修改 MiniApplicationContext)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
private Object createBean(String beanName, BeanDefinition beanDefinition) {
    Class<?> clazz = beanDefinition.getBeanClass();
    try {
        Object instance = doCreateInstance(clazz);
        populateBean(instance);

        if (instance instanceof MiniInitializingBean) {
            ((MiniInitializingBean) instance).afterPropertiesSet();
        }

        // 检查是否需要AOP代理
        instance = wrapIfNeeded(instance);

        return instance;
    } catch (Exception e) {
        throw new RuntimeException("Failed to create bean: " + beanName, e);
    }
}

private Object wrapIfNeeded(Object bean) {
    Class<?> clazz = bean.getClass();
    if (clazz.isAnnotationPresent(MiniAspect.class)) {
        return MiniProxyFactory.createProxy(bean, new MiniMethodInterceptor() {
            @Override
            public Object invoke(Method method, Object[] args, Object target) throws Throwable {
                System.out.println("🔥 [MiniAOP] Before method: " + method.getName());
                Object result = method.invoke(target, args);
                System.out.println("✅ [MiniAOP] After method: " + method.getName());
                return result;
            }
        });
    }
    return bean;
}
5. 测试案例:带接口的业务Bean(走 JDK代理)
1
2
3
public interface IOrderService {
    void createOrder();
}

实现:

1
2
3
4
5
6
7
8
@MiniComponent
@MiniAspect
public class OrderService implements IOrderService {
    @Override
    public void createOrder() {
        System.out.println("创建订单...");
    }
}
6. 测试案例:没有接口的业务Bean(走 CGLIB代理)
1
2
3
4
5
6
7
@MiniComponent
@MiniAspect
public class UserService {
    public void registerUser() {
        System.out.println("注册用户...");
    }
}
7. 测试启动
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
public class TestAop {
    public static void main(String[] args) {
        MiniApplicationContext context = new MiniApplicationContext("com.example.demo");

        IOrderService orderService = (IOrderService) context.getBean("orderService");
        orderService.createOrder();

        UserService userService = (UserService) context.getBean("userService");
        userService.registerUser();
    }
}

在V7.0,在v6的基础上实现以下功能:

  • 支持 切点表达式(Pointcut)
  • 支持 前置通知、后置通知、异常通知
  • 支持 环绕通知(Around)
  • 支持 MiniJoinPoint 参数传递
1. AOP 注解体系升级
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// 标记一个切面类
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MiniAspect {
}

// 标记一个切点方法
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MiniPointcut {
    String value(); // 支持方法名匹配,简单版
}

// 标记前置通知
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MiniBefore {
    String value();
}

// 标记后置通知
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MiniAfter {
    String value();
}

// 标记异常通知
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MiniAfterThrowing {
    String value();
}

// 标记环绕通知
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MiniAround {
    String value();
}
2. MiniJoinPoint接口,(类似 Spring的 `ProceedingJoinPoint`)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import java.lang.reflect.Method;

public class MiniJoinPoint {
    private Method method;
    private Object[] args;
    private Object target;

    public MiniJoinPoint(Method method, Object[] args, Object target) {
        this.method = method;
        this.args = args;
        this.target = target;
    }

    public Object proceed() throws Throwable {
        return method.invoke(target, args);
    }

    public Method getMethod() {
        return method;
    }

    public Object[] getArgs() {
        return args;
    }

    public Object getTarget() {
        return target;
    }
}
3. 定义切面执行器 MiniAspectExecutor
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

public class MiniAspectExecutor {
    private Object aspectBean;
    private List<Method> beforeMethods = new ArrayList<>();
    private List<Method> afterMethods = new ArrayList<>();
    private List<Method> throwingMethods = new ArrayList<>();
    private Method aroundMethod;
    private String matchMethodName; // 切点方法名匹配

    public MiniAspectExecutor(Object aspectBean, String matchMethodName) {
        this.aspectBean = aspectBean;
        this.matchMethodName = matchMethodName;

        for (Method method : aspectBean.getClass().getDeclaredMethods()) {
            if (method.isAnnotationPresent(MiniBefore.class)) {
                beforeMethods.add(method);
            }
            if (method.isAnnotationPresent(MiniAfter.class)) {
                afterMethods.add(method);
            }
            if (method.isAnnotationPresent(MiniAfterThrowing.class)) {
                throwingMethods.add(method);
            }
            if (method.isAnnotationPresent(MiniAround.class)) {
                aroundMethod = method;
            }
        }
    }

    public Object invoke(MiniJoinPoint joinPoint) throws Throwable {
        if (!joinPoint.getMethod().getName().equals(matchMethodName)) {
            return joinPoint.proceed();
        }

        try {
            for (Method before : beforeMethods) {
                before.invoke(aspectBean, joinPoint);
            }

            if (aroundMethod != null) {
                return aroundMethod.invoke(aspectBean, joinPoint);
            } else {
                Object result = joinPoint.proceed();
                for (Method after : afterMethods) {
                    after.invoke(aspectBean, joinPoint);
                }
                return result;
            }

        } catch (Throwable e) {
            for (Method throwing : throwingMethods) {
                throwing.invoke(aspectBean, joinPoint);
            }
            throw e;
        }
    }
}
4. 修改代理工厂:带切面处理
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

public class MiniProxyFactory {

    public static Object createProxy(Object target, MiniAspectExecutor aspectExecutor) {
        Class<?> targetClass = target.getClass();
        if (targetClass.getInterfaces().length > 0) {
            return Proxy.newProxyInstance(
                    targetClass.getClassLoader(),
                    targetClass.getInterfaces(),
                    (proxy, method, args) -> aspectExecutor.invoke(new MiniJoinPoint(method, args, target))
            );
        } else {
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(targetClass);
            enhancer.setCallback((MethodInterceptor) (obj, method, args, methodProxy) ->
                    aspectExecutor.invoke(new MiniJoinPoint(method, args, target))
            );
            return enhancer.create();
        }
    }
}
5. 修改容器(MiniApplicationContext)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
private void initAspect() {
    for (Object bean : singletonObjects.values()) {
        Class<?> clazz = bean.getClass();
        if (clazz.isAnnotationPresent(MiniAspect.class)) {
            for (Method method : clazz.getDeclaredMethods()) {
                if (method.isAnnotationPresent(MiniPointcut.class)) {
                    MiniPointcut pointcut = method.getAnnotation(MiniPointcut.class);
                    String matchMethodName = pointcut.value();
                    aspectExecutors.add(new MiniAspectExecutor(bean, matchMethodName));
                }
            }
        }
    }
}

然后在 createBean() 的 wrapIfNeeded()中统一代理:

1
2
3
4
5
6
private Object wrapIfNeeded(Object bean) {
    for (MiniAspectExecutor aspectExecutor : aspectExecutors) {
        return MiniProxyFactory.createProxy(bean, aspectExecutor);
    }
    return bean;
}
6. 测试启动
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
@MiniAspect
public class LogAspect {

    @MiniPointcut("createOrder")
    public void pointcut() {}

    @MiniBefore("createOrder")
    public void before(MiniJoinPoint joinPoint) {
        System.out.println("Before method: " + joinPoint.getMethod().getName());
    }

    @MiniAfter("createOrder")
    public void after(MiniJoinPoint joinPoint) {
        System.out.println("After method: " + joinPoint.getMethod().getName());
    }

    @MiniAfterThrowing("createOrder")
    public void afterThrowing(MiniJoinPoint joinPoint) {
        System.out.println("Exception in method: " + joinPoint.getMethod().getName());
    }

    @MiniAround("createOrder")
    public Object around(MiniJoinPoint joinPoint) throws Throwable {
        System.out.println("Around start: " + joinPoint.getMethod().getName());
        Object result = joinPoint.proceed();
        System.out.println("Around end: " + joinPoint.getMethod().getName());
        return result;
    }
}

最终体系一览(完整版)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
+-------------------------------------+
| MiniApplicationContext              |
|  - initAspect()                     |
|  - createBean()                     |
|  - wrapIfNeeded()                   |
+---------------------+---------------+
                      |
                      v
        +---------------------------+
        | MiniAspectExecutor         |
        |  - beforeMethods           |
        |  - afterMethods            |
        |  - throwingMethods         |
        |  - aroundMethod            |
        +---------------------------+
                      |
                      v
+------------------------+        +--------------------+
| MiniProxyFactory        |-----> | JDK Proxy / CGLIB    |
|  - createProxy()        |        +--------------------+
|  - apply aspectExecutor |
+------------------------+

2. 面向切面编程 (AOP)

目标:掌握 AOP 核心概念、通知类型、切点表达式、Spring AOP 实现原理及配置方法,通过示例深入理解切面逻辑的织入与执行顺序。

2.1 AOP 基本概念

概念 通俗解释 具象化小故事
切面 (Aspect) 一个功能模块,用来统一处理某种横跨多个地方的需求,比如日志、权限校验、事务控制。 想象成“保安小队”:到每栋楼都要巡逻检查。日志切面、事务切面,就是不同的小队。
通知 (Advice) 切面里具体要做的事情。比如:在方法执行前打个日志,或者执行后发个报警。 保安小队里每个人的“任务动作”:比如敲门、登记、拍照。
连接点 (JoinPoint) 程序运行时能插手的位置。在Spring AOP里,基本就是"每次调用方法"的时候。 楼宇的每一个门口。保安可以在门口做登记。每个方法入口就是一个门口。
切点 (Pointcut) 用规则选中某些连接点。告诉Spring在哪些方法门口安排保安。 告诉保安:只去“办公室楼层”的门口巡逻,不用去仓库。比如:只拦截com.xx.service.*方法。
织入 (Weaving) 把切面(保安任务)真正套到目标对象上 保安真的走到指定门口开始执勤。Spring AOP就是在运行时,用动态代理让保安附着到楼门上。

再用一个实际例子记忆

比如你写了个用户登录系统:

  • 希望所有登录相关的方法,都统一加日志记录
  • 又希望某些敏感操作,要统一加权限校验

你可以这样想:

场景 AOP对应术语
定义一个“日志记录切面” Aspect(切面)
里面有“方法调用前打日志”的动作 Advice(通知)
方法真正被调用时,插入日志动作 JoinPoint(连接点)
选择“所有以login开头的方法” Pointcut(切点)
程序运行时,代理对象拦截方法,插入日志 Weaving(织入)

2.2 通知 (Advice) 类型

通知类型 注解 含义
前置通知 @Before 方法执行之前执行
后置通知 @After 方法执行完成后执行(不管成功/异常都会执行)
返回通知 @AfterReturning 方法成功返回后执行
异常通知 @AfterThrowing 方法抛出异常后执行
环绕通知 @Around 方法执行前后都可以控制,最强大

示例:包含全部5种通知

  • @Pointcut 用来定义一个统一的切点表达式,供多个通知共享。
  • @Before执行方法之前干活。
  • @After无论成功或异常,总之方法执行后都会执行(有点像 finally 块)。
  • @AfterReturning方法成功返回之后,如果抛异常不会执行。
  • @AfterThrowing方法抛出异常时才执行。
  • @Around 最强大,可以手动决定是否执行原方法 (proceed() 调用),还能控制返回值。
包含全部5种通知
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class MyAspect {

    // 切点表达式:拦截所有 service 包下的方法
    @Pointcut("execution(* com.example.service..*(..))")
    public void serviceMethods() {
    }

    // 1. 前置通知
    @Before("serviceMethods()")
    public void beforeAdvice() {
        System.out.println("【前置通知】方法即将执行!");
    }

    // 2. 后置通知
    @After("serviceMethods()")
    public void afterAdvice() {
        System.out.println("【后置通知】方法已经执行完成(无论成功失败)!");
    }

    // 3. 返回通知
    @AfterReturning("serviceMethods()")
    public void afterReturningAdvice() {
        System.out.println("【返回通知】方法成功返回!");
    }

    // 4. 异常通知
    @AfterThrowing("serviceMethods()")
    public void afterThrowingAdvice() {
        System.out.println("【异常通知】方法出现异常了!");
    }

    // 5. 环绕通知
    @Around("serviceMethods()")
    public Object aroundAdvice(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("【环绕通知-前】即将执行方法:" + pjp.getSignature());
        Object result = pjp.proceed(); // 执行目标方法
        System.out.println("【环绕通知-后】方法执行完毕:" + pjp.getSignature());
        return result;
    }
}
启动测试
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
@Service
public class UserService {
    public void register(String username) {
        System.out.println(username + " 注册成功!");
        // throw new RuntimeException("模拟异常"); // 取消注释可以测试异常通知
    }
}

如果正常调用
userService.register("Alice");

控制台输出
环绕通知-即将执行方法void com.example.service.UserService.register(String)
前置通知方法即将执行
Alice 注册成功
后置通知方法已经执行完成无论成功失败)!
返回通知方法成功返回
环绕通知-方法执行完毕void com.example.service.UserService.register(String)

2.3 切点表达式 (Pointcut Expressions)

  • execution
    • 语法: execution([修饰符] 返回值类型 [包名.]类名.方法名(参数列表))
    • 示例: execution(public com.example.service.UserService.(..)),匹配 com.example.service.UserService 类中所有 public 方法,参数任意
    • 示例: execution(* com.example..Service.find(..)),匹配 com.example 包及子包下,所有名字以 find 开头的方法,返回值任意
  • within:within匹配某类或包下面的方法
    • 语法: within(完整类名或包名..)
    • 示例: within(com.example.service.UserService),匹配 UserService 类里的所有方法
    • 示例: within(com.example.service..*),匹配 com.example.service 包及其子包下所有类的所有方法
  • this/target:this 和 target(代理对象 or 目标对象类型)
    • 语法: this(A):当前代理对象是 A 类型,target(A):当前目标对象是 A 类型
    • 示例: this(com.example.service.UserService),如果是用 接口代理(JDK动态代理),需要注意接口与实现类的区别
    • 示例: target(com.example.service.impl.UserServiceImpl),无论代理还是目标,最终落到 UserServiceImpl 实现类上,都匹配。
    • CGLIB代理时this和target基本一致,JDK代理时不同
  • args:匹配方法参数类型。
    • 语法:args(参数类型列表)
    • 示例:args(java.lang.String),匹配只有一个参数,且是 String 类型的方法
    • 示例:args(java.lang.String, ..),匹配第一个参数是 String,后面可以有任意多个参数的方法
  • @annotation:匹配方法上有某个注解。
    • 语法:@annotation(注解类名)
    • 示例:@annotation(org.springframework.transaction.annotation.Transactional),匹配被 @Transactional 标注的方法

示例:拦截com.example.service 包下的所有 *Service 类,方法名以 find 开头,并且方法上标了自定义注解 @MyLog,在方法执行前打印日志。

1. 创建注解 @MyLog
1
2
3
4
5
6
7
8
package com.example.annotation;

import java.lang.annotation.*;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyLog {
}
2. 创建一个业务类 UserService
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package com.example.service;

import com.example.annotation.MyLog;
import org.springframework.stereotype.Service;

@Service
public class UserService {

    @MyLog
    public String findUserById(String id) {
        System.out.println("执行 findUserById 逻辑,参数:" + id);
        return "User:" + id;
    }

    public String updateUser(String id) {
        System.out.println("执行 updateUser 逻辑,参数:" + id);
        return "Updated User:" + id;
    }
}

注意
- `findUserById`  `@MyLog`
- `updateUser` 没有 `@MyLog`
3. 创建切面类 LogAspect
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
package com.example.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class LogAspect {

    // execution(* com.example.service.*Service.find*(..)) , ➔ 包 + 类名 + 方法名规则匹配。
    // @annotation(com.example.annotation.MyLog) , ➔ 方法必须标注了 @MyLog 注解。
    // 两者 && 联合生效
    @Before("execution(* com.example.service.*Service.find*(..)) && @annotation(com.example.annotation.MyLog)")
    public void logBefore(JoinPoint joinPoint) {
        System.out.println("[日志切面] 方法调用前:" + joinPoint.getSignature());
    }
}
4. 启动测试
  1. Spring Boot 配置启用 AOP application.properties: spring.aop.proxy-target-class=true 默认开启了 AOP,不需要特别额外操作。 如果是纯 Spring 项目,需要加:@EnableAspectJAutoProxy
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
@Autowired
private UserService userService;

@Test
public void testFindUser() {
    userService.findUserById("123");
    userService.updateUser("456");
}

[日志切面] 方法调用前String com.example.service.UserService.findUserById(String)
执行 findUserById 逻辑参数123
执行 updateUser 逻辑参数456

示例:拦截任意 service 方法,方法执行前后都可以插入逻辑,可以拿到参数、可以改返回值、可以统一异常处理!

1. 先定义一个注解:@Monitor
1
2
3
4
5
6
7
8
9
package com.example.annotation;

import java.lang.annotation.*;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Monitor {
    String value() default "";
}
2. 写业务方法:OrderService
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
package com.example.service;

import com.example.annotation.Monitor;
import org.springframework.stereotype.Service;

@Service
public class OrderService {

    @Monitor("下单接口")
    public String createOrder(String productId) {
        System.out.println("执行 createOrder,商品ID:" + productId);
        return "订单号: " + System.currentTimeMillis();
    }

    public String cancelOrder(String orderId) {
        System.out.println("执行 cancelOrder,订单ID:" + orderId);
        return "取消成功";
    }
}
3. 创建一个超强 Around 切面
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
package com.example.aspect;

import com.example.annotation.Monitor;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class MonitorAspect {

    @Around("@annotation(monitor)")
    public Object around(ProceedingJoinPoint pjp, Monitor monitor) throws Throwable {
        String methodName = pjp.getSignature().toShortString();
        Object[] args = pjp.getArgs();
        long start = System.currentTimeMillis();

        System.out.println("[Monitor] 开始调用方法:" + methodName + ",描述:" + monitor.value());
        System.out.println("[Monitor] 参数:" + java.util.Arrays.toString(args));

        Object result = null;
        try {
            result = pjp.proceed();  // 继续执行目标方法
            System.out.println("[Monitor] 方法正常返回,结果:" + result);
        } catch (Throwable ex) {
            System.out.println("[Monitor] 方法抛出异常:" + ex.getMessage());
            throw ex; // 记得重新抛出
        } finally {
            long end = System.currentTimeMillis();
            System.out.println("[Monitor] 方法耗时:" + (end - start) + " ms");
        }

        // 可以在这里,改变返回值
        return result;
    }
}
4. 启动测试
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
@Autowired
private OrderService orderService;

@Test
public void testCreateOrder() {
    String result = orderService.createOrder("P001");
    System.out.println("最终返回结果:" + result);
}

@Test
public void testCancelOrder() {
    String result = orderService.cancelOrder("O123");
    System.out.println("最终返回结果:" + result);
}
6. 测试输出
1
2
3
4
5
6
[Monitor] 开始调用方法:OrderService.createOrder(..),描述:下单接口
[Monitor] 参数:[P001]
执行 createOrder,商品ID:P001
[Monitor] 方法正常返回,结果:订单号: 1714333444110
[Monitor] 方法耗时:12 ms
最终返回结果:订单号: 1714333444110

2.4 Spring AOP 实现原理

  • 动态代理
    Spring AOP 是基于动态代理实现的,有两种方式:

    • JDK 动态代理:如果目标对象实现了接口,就用 JDK Proxy。
    • CGLIB 动态代理:如果目标对象没有接口,就用 CGLIB 生成子类代理。
  • Advisor 与 Advice

    • Advice:通知,比如 BeforeAdvice、AfterAdvice 等。
    • Advisor:= Pointcut(切点) + Advice(通知)
      ⇒ Advisor 其实是切点+通知的绑定器
  • BeanPostProcessor —— 代理生成关键

    • 核心类:AnnotationAwareAspectJAutoProxyCreator
    • 这个 BeanPostProcessor 在 Spring 容器创建 Bean 后,会检查:
      • 是否需要为这个 Bean 创建代理。
      • 如果需要,就动态生成代理对象,替换原来的 Bean!
  • 织入流程(Weaving)

    • 解析切面类(@Aspect),找出 Pointcut 和 Advice。
    • 为每个普通 Bean 检查是否匹配 Advisor。
    • 如果匹配:
      • 创建代理(Proxy)。
      • 把原 Bean 换成代理 Bean。

整体流程图

Bean初始化流程
    ↓
AnnotationAwareAspectJAutoProxyCreator
    ↓
扫描所有切面(Advisor)
    ↓
给当前Bean匹配合适的Advisor
    ↓
需要增强?
    ↓
是 → 创建代理对象(JDK / CGLIB)
否 → 保持原样

详细分步骤版

步骤 内容
1 Spring 启动时,@Aspect 注解的切面类会被解析,注册成 Advisor。
2 每次有 Bean 初始化时,AnnotationAwareAspectJAutoProxyCreator 介入。
3 给这个 Bean 找一圈,哪些 Advisor 能作用在它身上。
4 如果找到了,就用 JDK Proxy / CGLIB 生成代理对象。
5 把代理对象注册进容器,代替原来的 Bean。
6 调用代理对象时,会走 Advice 逻辑,比如前置、后置、环绕通知。

Spring AOP = 容器后处理 + 自动织入 + 动态代理

示例:开启注解驱动

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
// 声明这是一个配置类(相当于 XML 配置文件)
@Configuration 
// 自动向容器中注入了 AnnotationAwareAspectJAutoProxyCreator 这个超核心的 BeanPostProcessor!
// 这个 Processor 能:扫描所有的切面(@Aspect),动态为匹配的 Bean 生成代理对象,实现横切逻辑(Before、After、Around等)
// proxyTargetClass = false(默认),false:优先用 JDK 动态代理(接口代理),如果有接口就用接口;true:强制用 CGLIB 子类代理(即使有接口也不用 JDK Proxy)。
// exposeProxy是否把代理对象暴露到当前线程上下文?true:可以通过 AopContext.currentProxy() 获取到当前的代理对象;false:默认不暴露。
@EnableAspectJAutoProxy(proxyTargetClass = false, exposeProxy = true)
// 扫描 com.example 包,自动注册组件(比如你的 Service、Controller、Aspect类)
@ComponentScan("com.example") 
public class AopConfig {}

2.5 使用与测试

示例:

1. 依赖准备
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<!-- Spring AOP -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aop</artifactId>
</dependency>

<!-- AspectJ Runtime (织入支持) -->
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
</dependency>

<!-- Spring Test 测试支持 -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test</artifactId>
</dependency>

<!-- JUnit5 -->
<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter</artifactId>
</dependency>
2. 配置类(AopConfig)
1
2
3
4
5
@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = false) // 开启 AOP 自动代理
@ComponentScan("com.example") // 扫描 Service 和 Aspect
public class AopConfig {
}
3. 业务类(Service)
1
2
3
4
5
6
@Service
public class MyService {
    public void doWork(String taskName) {
        System.out.println("Doing work: " + taskName);
    }
}
4. 切面类(Aspect)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Aspect
@Component
public class LoggingAspect {

    @Around("execution(* com.example.MyService.doWork(..))")
    public Object aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("[AROUND BEFORE] - " + joinPoint.getSignature().getName());
        Object result = joinPoint.proceed(); // 调用目标方法
        System.out.println("[AROUND AFTER] - " + joinPoint.getSignature().getName());
        return result;
    }

    @Before("execution(* com.example.MyService.doWork(..))")
    public void beforeAdvice(JoinPoint joinPoint) {
        System.out.println("[BEFORE] - " + joinPoint.getSignature().getName());
    }

    @AfterReturning("execution(* com.example.MyService.doWork(..))")
    public void afterReturningAdvice(JoinPoint joinPoint) {
        System.out.println("[AFTER RETURNING] - " + joinPoint.getSignature().getName());
    }
}
5. 测试启动
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
// 让 JUnit5 支持 Spring
@ExtendWith(SpringExtension.class)
// 告诉测试用哪个 Spring 配置
@ContextConfiguration(classes = {AopConfig.class, MyService.class, LoggingAspect.class})
public class AopTest {

    @Autowired
    private MyService service;

    @Test
    void testAspect() {
        service.doWork("test");
        // 观察控制台:[AROUND BEFORE] ... [BEFORE] ... Doing work: test ... [AFTER RETURNING] ... [AROUND AFTER]
    }
}
6. 测试结果
1
2
3
4
5
[AROUND BEFORE] - doWork
[BEFORE] - doWork
Doing work: test
[AFTER RETURNING] - doWork
[AROUND AFTER] - doWork

示例:

1. 目录结构
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
src/main/java/
 └── com/example/
      ├── config/
      │    └── MyConfig.java
      ├── aspect/
      │    └── LoggingAspect.java
      ├── service/
      │    └── MyService.java
src/test/java/
 └── com/example/
      └── AopTest.java
2. 配置类:MyConfig.java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
package com.example.config;

import com.example.aspect.LoggingAspect;
import com.example.service.MyService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configuration
@EnableAspectJAutoProxy
public class MyConfig {

    @Bean
    public MyService myService() {
        return new MyService();
    }

    @Bean
    public LoggingAspect loggingAspect() {
        return new LoggingAspect();
    }
}
3. 业务类:MyService.java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
package com.example.service;

import org.springframework.stereotype.Service;

@Service
public class MyService {

    public void doWork(String task) {
        System.out.println("Doing work on: " + task);
    }

    public void doOtherWork() {
        System.out.println("Doing other work");
    }

    public String riskyOperation(String input) {
        if (input == null) {
            throw new IllegalArgumentException("Input must not be null");
        }
        return "Processed: " + input;
    }
}
4. 切面类:LoggingAspect.java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
package com.example.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.ProceedingJoinPoint;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class LoggingAspect {

    // 只拦截 doWork 方法
    @Pointcut("execution(* com.example.service.MyService.doWork(..))")
    public void workPointcut() {}

    // 只拦截 riskyOperation 方法
    @Pointcut("execution(* com.example.service.MyService.riskyOperation(..))")
    public void riskyPointcut() {}

    // 通用 Before
    @Before("workPointcut()")
    public void beforeWork(JoinPoint joinPoint) {
        System.out.println("[Before] " + joinPoint.getSignature().getName() + ", args: " + joinPoint.getArgs()[0]);
    }

    // Around 带参数打印
    @Around("workPointcut()")
    public Object aroundWork(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("[Around Before] " + pjp.getSignature().getName());
        Object result = pjp.proceed();
        System.out.println("[Around After] " + pjp.getSignature().getName());
        return result;
    }

    // AfterReturning
    @AfterReturning(value = "workPointcut()", returning = "result")
    public void afterReturningWork(JoinPoint joinPoint, Object result) {
        System.out.println("[AfterReturning] " + joinPoint.getSignature().getName());
    }

    // AfterThrowing 专门处理 riskyOperation 抛异常的情况
    @AfterThrowing(value = "riskyPointcut()", throwing = "ex")
    public void afterThrowingRisky(JoinPoint joinPoint, Exception ex) {
        System.out.println("[AfterThrowing] " + joinPoint.getSignature().getName() + ", Exception: " + ex.getMessage());
    }

    // 通用 After
    @After("workPointcut() || riskyPointcut()")
    public void afterAny(JoinPoint joinPoint) {
        System.out.println("[After] " + joinPoint.getSignature().getName());
    }
}
5. 测试类:AopTest.java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
package com.example;

import com.example.config.MyConfig;
import com.example.service.MyService;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;

@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = MyConfig.class)
public class AopTest {

    @Autowired
    private MyService myService;

    // Around Before ➔ Before ➔ 业务方法 ➔ AfterReturning ➔ After ➔ Around After
    @Test
    void testDoWork() {
        myService.doWork("TestTask");
    }

    @Test
    void testDoOtherWork() {
        myService.doOtherWork(); // 这个不会被AOP拦截
    }

    // 正常流程:业务方法 ➔ After
    @Test
    void testRiskyOperation_success() {
        String result = myService.riskyOperation("safe input");
        System.out.println("Result: " + result);
    }

    // 抛异常:AfterThrowing 捕获异常 ➔ After
    @Test
    void testRiskyOperation_fail() {
        try {
            myService.riskyOperation(null);
        } catch (Exception ignored) {
        }
    }
}

3. 数据访问与事务管理(Data Access & Tx)

Spring 给我们提供了数据访问机制(JdbcTemplate、ORM、MyBatis)与事务控制(声明式事务、事务传播、隔离级别、多数据源与分布式事务等)。

3.1 JdbcTemplate

  • 概念:Spring JDBC 提供的 JdbcTemplate 简化了原生 JDBC API 的样板代码,自动管理连接获取、异常翻译、资源关闭,提升开发效率。
  • 配置:注入 DataSource,可通过 DriverManagerDataSource、连接池(HikariCP、Druid)等实现。
  • 提供统一的异常封装:Spring 将 JDBC 异常封装为 DataAccessException 及其子类,便于统一捕获与恢复。

配置示例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
@Configuration
public class DataSourceConfig {
    @Bean
    public DataSource dataSource() {
        DriverManagerDataSource ds = new DriverManagerDataSource();
        ds.setDriverClassName("com.mysql.cj.jdbc.Driver");
        ds.setUrl("jdbc:mysql://localhost:3306/testdb");
        ds.setUsername("root");
        ds.setPassword("password");
        return ds;
    }

    @Bean
    public JdbcTemplate jdbcTemplate(DataSource ds) {
        return new JdbcTemplate(ds);
    }
}

常用 API

  • jdbcTemplate.update(sql, args...):执行 INSERT/UPDATE/DELETE
  • jdbcTemplate.queryForObject(sql, rowMapper, args...):单行结果
  • jdbcTemplate.query(sql, rowMapper, args...):多行结果
  • jdbcTemplate.batchUpdate(sql, batchArgs):批量更新
  • jdbcTemplate.queryForList(sql, elementType):返回简单类型列表
示例 DAO
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
@Repository
public class UserDao {
    private final JdbcTemplate jdbc;

    public UserDao(JdbcTemplate jdbc) { this.jdbc = jdbc; }

    public int save(User u) {
        return jdbc.update(
            "INSERT INTO users(username, registered_at) VALUES(?, ?)",
            u.getUsername(), u.getRegisteredAt());
    }

    public User findById(Long id) {
        return jdbc.queryForObject(
            "SELECT id, username, registered_at FROM users WHERE id = ?", 
            (rs, rn) -new User(
                rs.getLong("id"), rs.getString("username"), rs.getTimestamp("registered_at").toLocalDateTime()),
            id);
    }

    public List<UserfindAll() {
        return jdbc.query(
            "SELECT id, username, registered_at FROM users", 
            (rs, rn) -new User(
                rs.getLong("id"), rs.getString("username"), rs.getTimestamp("registered_at").toLocalDateTime()));
    }
}

3.2 ORM 集成(Hibernate / JPA)

  • 概念:JPA(Java Persistence API)定义了 ORM 标准,Hibernate 是常用实现。Spring 通过 LocalContainerEntityManagerFactoryBeanLocalSessionFactoryBean 集成。
  • 配置
    • 数据源同 JdbcTemplate
    • 实体扫描packagesToScan
    • 方言、DDL 自动化等属性
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Configuration
@EnableTransactionManagement
public class JpaConfig {
    @Bean
    public LocalContainerEntityManagerFactoryBean emf(DataSource ds) {
        LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean();
        emf.setDataSource(ds);
        emf.setPackagesToScan("com.example.domain");
        JpaVendorAdapter vendor = new HibernateJpaVendorAdapter();
        emf.setJpaVendorAdapter(vendor);
        Properties props = new Properties();
        props.put("hibernate.hbm2ddl.auto", "update");
        props.put("hibernate.dialect", "org.hibernate.dialect.MySQL8Dialect");
        emf.setJpaProperties(props);
        return emf;
    }

    @Bean
    public PlatformTransactionManager transactionManager(EntityManagerFactory emf) {
        return new JpaTransactionManager(emf);
    }
}
  • 使用:在实体类上使用 @Entity@Table@Id@GeneratedValue 标注;在 Repository 接口继承 JpaRepository 或手写 @Repository + EntityManager

示例:Spring Data JPA

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
@Entity
@Table(name = "products")
public class Product {
    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    // getters/setters
}

@Repository
public interface ProductRepo extends JpaRepository<Product, Long{
    List<ProductfindByNameContaining(String keyword);
}

3.3 SQLSession & MyBatis 支持

概述:Spring 与 MyBatis 深度集成,MyBatis 提供灵活的 SQL 编写方式,适用于对 SQL 控制精细的场景。

关键点

  • Mapper 接口 + XML 映射
  • 与 Spring Boot 自动配置集成
  • 支持分页插件、缓存等功能

示例代码

1
2
3
4
5
@Mapper
public interface UserMapper {
    @Select("SELECT * FROM users WHERE id = #{id}")
    User findById(Long id);
}

3.4 Spring Data 简介

概述:Spring Data 提供统一的数据访问抽象,主要子项目有 Spring Data JPA、MongoDB、Redis 等,专注于简化 DAO 层开发。

  • Repository 接口自动实现
  • 方法命名自动派生 SQL
  • 自定义查询(@Query / QueryDSL)

示例代码

1
2
3
4
5
6
public interface OrderRepository extends JpaRepository<Order, Long> {
    List<Order> findByStatus(String status);

    @Query("SELECT o FROM Order o WHERE o.total > ?1")
    List<Order> findExpensiveOrders(BigDecimal minTotal);
}

3.5 异常处理与统一封装

概述:Spring 对底层数据库异常进行了统一封装,避免因不同厂商的 SQL 异常而影响业务逻辑。

  • DataAccessException 统一异常体系
  • 不再暴露 JDBC 原生异常(如 SQLException)

示例代码

1
2
3
4
5
6
try {
    jdbcTemplate.update("INSERT INTO users(name) VALUES(?)", "Tom");
} catch (DataAccessException e) {
    // 统一处理数据库异常
    logger.error("Database error: " + e.getMessage());
}

3.6 事务管理

  • 概念:事务保证操作的原子性、一致性、隔离性、持久性(ACID)。Spring 提供统一抽象 PlatformTransactionManager,支持声明式和编程式事务。支持多种事务管理器(DataSource、JPA、Hibernate、JTA)。
  • 声明式事务:通过 @EnableTransactionManagement + @Transactional 自动代理,无需手动管理事务边界。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
@Service
public class OrderService {
    @Transactional(
        propagation = Propagation.REQUIRED,
        isolation = Isolation.READ_COMMITTED,
        rollbackFor = Exception.class,
        readOnly = false
    )
    public void placeOrder(Order order) {
        orderRepo.save(order);
        auditRepo.log(order);
        // 任意异常将触发回滚
    }
}
  • 事务属性
    • 传播行为(Propagation):REQUIRED、REQUIRES_NEW、NESTED 等,控制事务如何嵌套。
    • 隔离级别(Isolation):READ_UNCOMMITTED、READ_COMMITTED、REPEATABLE_READ、SERIALIZABLE,防止脏读、不可重复读、幻读。
    • 只读(readOnly):提示底层只需读操作,可优化性能。
    • 回滚策略rollbackFornoRollbackFor 控制哪些异常触发回滚。

测试事务

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = {DataSourceConfig.class, JpaConfig.class, OrderService.class, OrderRepo.class, AuditRepo.class})
public class TransactionTest {
    @Autowired
    private OrderService service;

    @Test
    void testRollback() {
        assertThrows(RuntimeException.class, () -{
            service.placeOrder(invalidOrder());
        });
        // 验证 orderRepo 和 auditRepo 均未提交数据
    }
}

3.7 分布式事务与多数据源支持

概述:Spring 支持多数据源和 JTA 分布式事务(如 Atomikos、Narayana)。

  • 配置多个 DataSource Bean(每个对应不同数据库)
  • 指定事务管理器:使用 @Transactional(transactionManager = “xxx”) 绑定特定数据源的事务
  • 分布式事务使用 XA 事务管理器,如 Atomikos、Narayana
  • 推荐方案:使用 Seata / TCC 模式 替代传统 XA 分布式事务,更高效、更易扩展
多数据源配置示例(以 Spring Java Config 为例)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
@Configuration
public class MultiDataSourceConfig {

    @Bean
    @Primary
    public DataSource dataSource1() {
        DriverManagerDataSource ds = new DriverManagerDataSource();
        ds.setUrl("jdbc:mysql://localhost:3306/db1");
        ds.setUsername("user1");
        ds.setPassword("pass1");
        return ds;
    }

    @Bean
    public DataSource dataSource2() {
        DriverManagerDataSource ds = new DriverManagerDataSource();
        ds.setUrl("jdbc:mysql://localhost:3306/db2");
        ds.setUsername("user2");
        ds.setPassword("pass2");
        return ds;
    }

    @Bean
    @Primary
    public PlatformTransactionManager txManager1(@Qualifier("dataSource1") DataSource ds) {
        return new DataSourceTransactionManager(ds);
    }

    @Bean
    public PlatformTransactionManager txManager2(@Qualifier("dataSource2") DataSource ds) {
        return new DataSourceTransactionManager(ds);
    }
}
使用注解指定事务管理器
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
@Service
public class MultiDbService {

    @Autowired
    private UserRepo1 userRepo1;

    @Autowired
    private UserRepo2 userRepo2;

    // 使用第一个数据源事务管理器
    @Transactional(transactionManager = "txManager1")
    public void saveToDb1(User user) {
        userRepo1.save(user);
    }

    // 使用第二个数据源事务管理器
    @Transactional(transactionManager = "txManager2")
    public void saveToDb2(User user) {
        userRepo2.save(user);
    }
}

分布式事务方案(XA vs Seata)

传统 XA 模式:

  • 借助 Atomikos、Bitronix、Narayana 等实现
  • 依赖底层数据库支持 XA 协议
  • 配置复杂、性能较差,适用于强一致性业务场景

推荐替代方案:

  • Seata:支持 AT/TCC/SAGA/XA 模式的分布式事务协调器,适合微服务架构
  • TCC 模式:将 Try/Confirm/Cancel 拆分成显式三步,业务侵入较强,但性能优秀

总结

Spring框架必知必会,继续努力。