Spring AOP可以采用注解或者xml配置的方式实现,那么在spring的生命周期当中,是在什么时候生成的代理对象呢?本文就AOP代理对象生成的时机进行介绍。不清楚spring生命周期的读者可以先阅读另一篇博客《Spring IOC—Bean的生命周期》。
简单的讲就是在一个对象初始化的前后做一些事情,里面有两个方法,一个是postProcessBeforeInitialization,实例化、依赖注入完毕,在调用显示的初始化之前完成一些定制的初始化任务。另一个是postProcessAfterInitialization,实例化、依赖注入、初始化完毕时执行
可以分成两类,提前和非提前生成代理对象。
下面分别介绍这两类代理对象生成的时机,以及说明为什么会有这两种情况。
下面给个例子,通过调试代码来说明代理的时机,读者可以跟着一边调试一边阅读。
//被代理类 A
package hdu.gongsenlin.aoptest.dao;
@Component
public class A {
public void f(){
System.out.println("AAAAA");
}
}
//切面类
package hdu.gongsenlin.aoptest.aop;
@Aspect
@Component
public class Aop {
@Pointcut("execution(* hdu.gongsenlin.aoptest.dao..*.*(..))")
private void pointcut(){}
@After("pointcut()")
public void advice(){
System.out.println("之后增强------------");
}
}
//配置类
package hdu.gongsenlin.aoptest;
@Configuration
@ComponentScan("hdu.gongsenlin.aoptest")
@EnableAspectJAutoProxy
public class Appconfig {
}
//启动类
package hdu.gongsenlin.aoptest;
public class AoptestApplication {
public static void main(String[] args) {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(Appconfig.class);
A a = ac.getBean(A.class);
a.f();
}
}
上面的代码AOP会作用在A对象上,也就是生成A的代理对象。
这一过程发生在A的生命周期当中,将代码定位到AbstractAutowireCapableBeanFactory#doCreateBean方法
了解springBean的生命周期的读者都应该清楚,Bean生命周期中有一步是属性填充 population,在属性填充之后会执行initializeBean
initializeBean方法中会执行applyBeanPostProcessorsAfterInitialization方法
applyBeanPostProcessorsAfterInitialization具体的代码如下:
@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessAfterInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
逻辑比较简单,就是遍历所有实现了BeanPostProcessor接口的类,这里一共有这7个,一个一个去执行postProcessAfterInitialization方法。其中AnnotationAwareAspectJAutoProxyCreator就是会实现AOP动态代理,然后返回代理对象。
AnnotationAwareAspectJAutoProxyCreator中的postProcessAfterInitialization代码如下
根据bean类型和名字创建缓存key,判断earlyProxyReferences提前动态代理的集合当中存不存在这个缓存key,若存在则说明已经进行过动态代理了,则不再进行动态代理,而本例子中,很明显是没有执行提前动态代理的,所以会执行wrapIfNecessary方法进行构建动态代理对象,本文仅介绍执行的时机,具体的动态代理的实现过程暂时先不考虑。
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
Object cacheKey = this.getCacheKey(bean.getClass(), beanName);
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
return this.wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
所以非提前生成代理对象 是在属性填充populateBean完成之后,执行了initializeBean方法的时候进行的动态代理。
这种情况比较的复杂,涉及到了循环依赖的问题,对于Bean的循环依赖不了解的读者,可以先阅读《Spring IOC—循环依赖》这篇博客再接着阅读。
同样的以举例的方式说明
//切面类 不变
package hdu.gongsenlin.aoptest.aop;
@Aspect
@Component
public class Aop {
@Pointcut("execution(* hdu.gongsenlin.aoptest.dao..*.*(..))")
private void pointcut(){}
@After("pointcut()")
public void advice(){
System.out.println("之后增强------------");
}
}
//启动类 不变
public class AoptestApplication {
public static void main(String[] args) {
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(Appconfig.class);
A a = ac.getBean(A.class);
a.f();
}
}
//配置类 不变
@Configuration
@ComponentScan("hdu.gongsenlin.aoptest")
@EnableAspectJAutoProxy
public class Appconfig {
}
//被代理对象 A 依赖了 普通对象B
package hdu.gongsenlin.aoptest.dao;
@Component
public class A {
@Autowired
B b;
public void f(){
System.out.println("AAAAA");
}
}
// 普通对象B 依赖了 A
package hdu.gongsenlin.aoptest.service;
@Component
public class B {
@Autowired
A a;
public void f(){
System.out.println("BBBBBBBB");
}
}
此时给的例子中,A和B相互依赖,形成了循环依赖,不同的是A需要被动态代理,而B不需要。
继续将代码定位到创建A的时候,还没有执行属性填充populateBean的位置,如下:
因为涉及到了循环依赖,所以准备三个框框,来代表循环依赖需要用到的三个集合。
至于这三个集合的作用 在循环依赖的博客中已经介绍了,这里就不再赘述。
在上面代码执行之前,会将a的工厂对象放入到singletonFactories,此时三个集合的情况如下:
之后执行构建A的populateBean进行属性填充,发现A依赖于B,而B又不存在于这三个集合当中,所以会递归的创建B,调用doCreateBean来构建B对象,和A相同,在执行populateBean填充属性之前,会将b的工厂对象放入到singletonFactories当中,此时三个集合的情况如下:
接着会执行构建B的populateBean进行属性填充,此时B依赖于A,所以会调用doGetBean的去找A对象
然后调用getSingleton,该方法是解决循环依赖的关键,代码如下:
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// Quick check for existing instance without full singleton lock
Object singletonObject = this.singletonObjects.get(beanName);//先从单例池中去获取
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {//如果单例池中没有,并且当前的bean正在创建
singletonObject = this.earlySingletonObjects.get(beanName);// 看看有没有提前暴露的不完整的Bean
if (singletonObject == null && allowEarlyReference) {// 如果还没有 且允许提前创建
synchronized (this.singletonObjects) {
// Consistent creation of early reference within full singleton lock
singletonObject = this.singletonObjects.get(beanName);// 再检查一次 singletonObjects 双重检查
if (singletonObject == null) {
singletonObject = this.earlySingletonObjects.get(beanName);// 再检查一次 earlySingletonObjects 双重检查
if (singletonObject == null) {//若都还没有
// 则获取beanName对应的单例工厂
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
//通过工厂创建一个对象
singletonObject = singletonFactory.getObject();
//将这个实例化的对象放入到earlySingletonObjects
this.earlySingletonObjects.put(beanName, singletonObject);
//从单例工厂中移除 这个工厂。
this.singletonFactories.remove(beanName);
}
}
}
}
}
}
return singletonObject;
}
一级缓存和二级缓存中没有找到A对象,而三级缓存singletonFactories当中有A的工厂对象,所以会调用
singletonFactory.getObject()来获得A对象。
这是之前添加工厂对象到singletonFactories的代码,所以其实执行getObject()也就是执行了getEarlyBeanReference方法
getEarlyBeanReference的方法代码如下:
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (SmartInstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().smartInstantiationAware) {
exposedObject = bp.getEarlyBeanReference(exposedObject, beanName);
}
}
return exposedObject;
}
此时又出现了AnnotationAwareAspectJAutoProxyCreator,这里会执行它的getEarlyBeanReference方法
基于类型和名字 创建缓存key,将其放入到earlyProxyReferences集合当中,用于表示进行了提前的动态代理。调用wrapIfNecessary来构建动态代理对象。
public Object getEarlyBeanReference(Object bean, String beanName) {
Object cacheKey = this.getCacheKey(bean.getClass(), beanName);
this.earlyProxyReferences.put(cacheKey, bean);
return this.wrapIfNecessary(bean, beanName, cacheKey);
}
此时获得到了被代理后的A对象,三个集合的结果如下:
之后doCreateBean 构建B的过程结束了,获得了B对象
之后会将这个对象,添加到singletonObjects集合当中,三个集合的结果如下:
B对象构建完成了,那么此时A就可以完成它的填充了,所以走完剩下的逻辑之后,三个集合的结果如下:
综上提前动态代理,其实是在依赖注入的时候,也就是在populateBean属性填充方法内完成的。
沿用3.2的例子,假设动态代理不提前,那么在构建B对象进行属性填充的时候,填充的A对象是还没有进行动态代理的A。
此时B就完成了它的生命周期到了单例池当中,而后A执行完属性填充之后,再进行动态代理,生成一个被代理的A对象。放入到单例池当中。
此时B中的A和单例池中的被代理的A对象不是同一个对象,这就造成了问题。