Spring AOP(面向切面编程)的动态代理是在 Bean 生命周期的 初始化后阶段 实现的,具体来说是在 BeanPostProcessor
的 postProcessAfterInitialization()
方法中完成的。下面我们来详细分析 Spring AOP 动态代理的实现位置及其工作原理。
1. Spring AOP 动态代理的实现位置
Spring AOP 的动态代理是通过 AnnotationAwareAspectJAutoProxyCreator
(一个 BeanPostProcessor
)在 Bean 生命周期的以下阶段实现的:
1.1 Bean 生命周期的初始化后阶段
- 在 Bean 初始化完成后(即
afterPropertiesSet()
或自定义的init-method
执行之后),Spring 会调用BeanPostProcessor
的postProcessAfterInitialization()
方法。 AnnotationAwareAspectJAutoProxyCreator
会在这个方法中检查当前 Bean 是否需要被代理。如果需要,则会创建代理对象并返回。
1.2 代理对象的生成
- 如果 Bean 符合切面规则(例如被
@Aspect
注解标记或匹配了切点表达式),Spring 会为其生成代理对象。 - 代理对象可以是 JDK 动态代理(基于接口)或 CGLIB 代理(基于类)。
2. Spring AOP 动态代理的工作流程
以下是 Spring AOP 动态代理的详细工作流程:
步骤 1:Bean 的实例化
- Spring 容器通过反射调用 Bean 的构造函数,创建 Bean 的实例。
步骤 2:属性注入
- Spring 容器根据配置为 Bean 注入依赖(如通过
@Autowired
或 XML 配置)。
步骤 3:初始化 Bean
- 如果 Bean 实现了
InitializingBean
接口,Spring 会调用afterPropertiesSet()
方法。 - 如果 Bean 配置了自定义的初始化方法(如
init-method
或@PostConstruct
),Spring 也会调用该方法。
步骤 4:BeanPostProcessor
的前置处理
- Spring 调用所有
BeanPostProcessor
的postProcessBeforeInitialization()
方法。 - 这个阶段通常用于在 Bean 初始化之前执行一些自定义逻辑。
步骤 5:BeanPostProcessor
的后置处理
- Spring 调用所有
BeanPostProcessor
的postProcessAfterInitialization()
方法。 AnnotationAwareAspectJAutoProxyCreator
会在这个阶段检查当前 Bean 是否需要被代理:- 如果需要代理,则生成代理对象并返回。
- 如果不需要代理,则直接返回原始 Bean。
步骤 6:Bean 就绪
- 此时,Bean 已经完成了所有初始化步骤,可以被应用程序使用了。
- 如果 Bean 被代理,则实际使用的是代理对象。
3. 动态代理的实现细节
Spring AOP 的动态代理有两种实现方式:
1. JDK 动态代理
- 如果目标类实现了接口,Spring 会使用 JDK 动态代理。
- 代理对象会实现目标类的接口,并将方法调用委托给目标对象。
2. CGLIB 代理
- 如果目标类没有实现接口,Spring 会使用 CGLIB 生成子类代理。
- 代理对象会继承目标类,并重写目标方法。
4. 源码分析
以下是 AnnotationAwareAspectJAutoProxyCreator
的核心逻辑:
java
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
if (bean != null) {
// 获取 Bean 的缓存键
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (!this.earlyProxyReferences.contains(cacheKey)) {
// 如果需要代理,则生成代理对象
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
// 检查是否需要代理
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
return bean;
}
// 获取适用于当前 Bean 的 Advisor(切面逻辑)
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
// 创建代理对象
this.advisedBeans.put(cacheKey, Boolean.TRUE);
return createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
}
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
postProcessAfterInitialization()
方法会在 Bean 初始化完成后调用。wrapIfNecessary()
方法会检查当前 Bean 是否需要代理,并在需要时生成代理对象。
5. 总结
Spring AOP 的动态代理是在 Bean 生命周期的 初始化后阶段 通过 BeanPostProcessor
的 postProcessAfterInitialization()
方法实现的。具体来说:
- 在 Bean 初始化完成后,
AnnotationAwareAspectJAutoProxyCreator
会检查当前 Bean 是否需要被代理。 - 如果需要代理,则生成代理对象并返回。
- 代理对象可以是 JDK 动态代理或 CGLIB 代理。
6. 面试回答建议
在面试中回答这个问题时,可以按照以下思路:
- 说明 Spring AOP 动态代理的实现位置(
BeanPostProcessor
的postProcessAfterInitialization()
方法)。 - 分析动态代理的两种实现方式(JDK 动态代理和 CGLIB 代理)。
- 结合实际项目经验,谈谈你是否使用过 Spring AOP 解决实际问题(如日志记录、事务管理等)。
- 提到 Spring AOP 的切面规则(如
@Aspect
、@Pointcut
等)。
这样回答既展示了你的技术深度,也体现了你对 Spring AOP 设计思想的理解。