攀登Spring珠穆朗玛峰:Spring AOP

使用方式

以最简单的注释式AOP为例。
被代理类

@Service
public class PersonService {
    public void exec() {
        System.out.println("exec person method...");
    }
}

切面类

@Component
@Aspect
public class PersonServiceAspect {
    @Pointcut("execution(* base.spring.service.PersonService..*(..))")
    public void point(){}
    
    @Before("point()")
    public void before(){
        System.out.println("before");
    }
    
    @After("point()")
    public void after(){
        System.out.println("after");
    }
}

启动类

@Configuration
@EnableAspectJAutoProxy
@ComponentScan("base.spring")
public class AppConifg {
}

class Test {
    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(AppConifg.class);
        context.getBean(PersonService.class).exec();
    }
}

执行结果:

before
exec person method...
after

原理解析

@EnableAspectJAutoProxy导入相关类

点开EnableAspectJAutoProxy的元注解信息。EnableAspectJAutoProxy注解有两个参数:

  • proxyTargetClass:强制使用CGLIB完成AOP代理;
  • exposeProxy:用来解决同一个类里方法调用只生效一次的问题;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
   boolean proxyTargetClass() default false;
   boolean exposeProxy() default false;
}

查看@Import导入的AspectJAutoProxyRegistrar

class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
   @Override
   public void registerBeanDefinitions(
         AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
	  //手动注册AOP代理过程中需要的类
      AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);

      AnnotationAttributes enableAspectJAutoProxy =
            AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
      if (enableAspectJAutoProxy != null) {
         if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
            AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
         }
         if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
            AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
         }
      }
   }

}

...
// registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source)    

Debug跟进注释处,可以发现最终手动注册了AnnotationAwareAspectJAutoProxyCreator类。

该类是SmartInstantiationAwareBeanPostProcessor的子接口,即这个类将被作为后置处理器参与到Spring的初始化当中。

什么时候进行AOP代理?

首先可以明确:Spring是利用后置处理器实现AOP代理的(即上文提到的AnnotationAwareAspectJAutoProxyCreator类)

Spring初始化(java config形式)的大体步骤可以概括为如下步骤:

  1. 先扫描类信息,然后转换成BeanDefinition并添加到BeanDefinitonMap中;
  2. 遍历BeanDefinitonMap,解析成创建时需要的描述信息(mergeBeanDefinition);
  3. 反射创建实例;
  4. 对实例进行属性填充(即创建实例内部的成员变量);
  5. 属性填充时,如果存在属性注入,则执行该属性的创建或者获取操作(未创建则创建,已创建则直接取);
  6. 完成属性填充
  7. 将该实例添加到Spring的单例池中,完成该类的初始化操作;

上述描述较为粗略,实际上比这个更细致,比如:

  • 实际不是直接遍历BeanDefinitionMap
  • 反射创建实例时需要推断构造器,通过后置处理器实现该功能;
  • 通过后置处理器完成属性填充;
  • 属性填充时可能发生循环依赖;
  • 等等……

更多的内容可以看以下文章:

Spring的AOP代理自然是要参与到上面的这个步骤的,因为最终添加到Spring单例池中的势必是代理后的对象。

那么Spring是什么时候进行代理的呢?

第1种情况

在属性填充完毕,基本完成该类的实例化后,调用后置处理器的方法, 对该类进行AOP代理。即上面的6~7步之间

这种情况很好理解:初始化一个类的时候,该类的属性都初始化完了,那么就该对该类进行代理了,代理结束后,就可以添加该类到单例池中,最终完成该类的初始化。这个 ”后置处理器的方法“ 就是postProcessAfterInitialization方法。

第2种情况

之所以还要提到第2种情况,是因为Spring的循环依赖问题。关于循环依赖,需要看上文提到的三级缓存方面的解析。举个例子

  • A类的成员变量注入了B类,B类的成员变量注入了A类,先初始化A。

这是个典型的循环依赖。Spring通过三级缓存解决了这个问题。过程不再描述。下面考虑一下AOP的情况:

  • 假定A类需要进行AOP代理(即通过@Aspect、@PointCut、@Before等注解识别到该类)

在新加入的这个前提下,初始化A时,需要初始化B,B需要获取A,然后因为A类处于创建中状态,然后从三级缓存里面获取到A类

那么这个这被 B 类所需要的A 类怎么办?(说起来比较绕,为方便讲述,以AA来表示这个类)

首先是AA类一定需要经过代理,否则单例池中的B类所包含的AA类的AOP配置就失效了。那么通过B类调用AA类,就没有了AOP处理的逻辑。

Spring的处理方式:当出现循环依赖需要获取AA类的时候,通过第三级缓存:singletonFactories调用后置处理器的getEarlyBeanReference方法。

可以查看这两个方法,都调用了wrapIfNecessary方法,wrapIfNecessary就是判断当前类是否需要进行代理,需要则代理,不需要则跳过。

postProcessAfterInitialization
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
    if (bean != null) {
        Object cacheKey = getCacheKey(bean.getClass(), beanName);
        //避免无意义的调用代理逻辑,缓存的作用
        if (this.earlyProxyReferences.remove(cacheKey) != bean) {
            return wrapIfNecessary(bean, beanName, cacheKey);
        }
    }
    return bean;
}
getEarlyBeanReference
@Override
public Object getEarlyBeanReference(Object bean, String beanName) {
   Object cacheKey = getCacheKey(bean.getClass(), beanName);
   this.earlyProxyReferences.put(cacheKey, bean);
   return wrapIfNecessary(bean, beanName, cacheKey);
}

有几点需要注意:

  • getEarlyBeanReference方法只有在出现循环依赖的时候才会被调用。
  • 不管有没有出现循环依赖都会调用postProcessAfterInitialization方法。
  • 出现循环依赖的时候,调用getEarlyBeanReference的AOP处理逻辑,实际上就不需要调用postProcessAfterInitialization的AOP处理逻辑了。因为已经代理过了一次,直接使用代理后的类即可。

为了避免无意义的逻辑调用,Spring使用三级缓存来解决了这个问题。

//AbstractAutoProxyCreator的成员变量:earlyProxyReferences,存储已经进行过代理的类。 
private final Map<Object, Object> earlyProxyReferences = new ConcurrentHashMap<>(16);

//1. 一级缓存:单例池,即通常意义下的Spring容器,SpringBean最终到达的地方  
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
//2.二级缓存:存储提前完成了代理的类  
private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);
//3.三级缓存:存储的ObjectFactory  
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

整理一下第2种情况的处理逻辑:

  1. 初始化A时,需要初始化B,B需要获取A,然后因为A类处于创建中状态,调用三级缓存singletonFactoriesgetObject方法,间接调用getEarlyBeanReference方法。
  2. getEarlyBeanReference方法内首先将当前A类(未被代理)存储到earlyProxyReferences集合中,标注A类进行过代理了。
  3. 执行完getEarlyBeanReference方法,代理创建AA类,将AA类存到二级缓存中;
  4. B类所需要的A类(代理后的)创建完毕,结束B的创建。
  5. 回到A的创建,A执行postProcessAfterInitialization方法。需要注意当前的A并没有被代理。
  6. 从earlyProxyReferences移除并获取A类,与当前类进行对比,都是没被代理过得类,且是同一个对象,证明当前类已经进行过代理了。跳过wrapIfNecessary的判断逻辑。
  7. 继续A的创建,注意此时A实际还是没有代理。此时尝试从spring的一二三级缓存里面获取A,最终在二级缓存里面获取到了AA类(第3步是添加,如果没有发生循环依赖,这个时候应当无法从二级缓存里面获取到)
  8. 使用二级缓存里面的AA替换当前的A
  9. 完成A的初始化。

这一块儿的内容,删删改改不知道怎么说。确实也比较绕。建议多Debug一下。这里贴一下相关的方法。

protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
      throws BeanCreationException {
	...
   Object exposedObject = bean;
   try {
      populateBean(beanName, mbd, instanceWrapper);
      exposedObject = initializeBean(beanName, exposedObject, mbd);
   }
   catch (Throwable ex) {
    ...
   }

   if (earlySingletonExposure) {
       //此处即是第7步,在这一步从二级缓存里面获取到了AA
      Object earlySingletonReference = getSingleton(beanName, false);
      if (earlySingletonReference != null) {
         if (exposedObject == bean) {
             //第8步,用AA替换A,完成A的初始化
            exposedObject = earlySingletonReference;
         }
         else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
            String[] dependentBeans = getDependentBeans(beanName);
            Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
            for (String dependentBean : dependentBeans) {
               if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
                  actualDependentBeans.add(dependentBean);
               }
            }
            if (!actualDependentBeans.isEmpty()) {
             ...
            }
         }
      }
   }
   ...
   return exposedObject;
}
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
   Object singletonObject = this.singletonObjects.get(beanName);
    //出现循环依赖时,进入下面的判断
   if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
      singletonObject = this.earlySingletonObjects.get(beanName);
      if (singletonObject == null && allowEarlyReference) {
         synchronized (this.singletonObjects) {
            singletonObject = this.singletonObjects.get(beanName);
            if (singletonObject == null) {
                //第7步,此时从二级缓存获取到了AA
               singletonObject = this.earlySingletonObjects.get(beanName);
               if (singletonObject == null) {
                  ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                  if (singletonFactory != null) {
                     singletonObject = singletonFactory.getObject();
                      //三级缓存移到二级缓存,完成了AA的创建,第2~3步
                     this.earlySingletonObjects.put(beanName, singletonObject);
                     this.singletonFactories.remove(beanName);
                  }
               }
            }
         }
      }
   }
   return singletonObject;
}

wrapIfNecessary逻辑

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
   if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
      return bean;
   }
   if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
      return bean;
   }
   //判断当前类是否需要进行代理
   if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
      this.advisedBeans.put(cacheKey, Boolean.FALSE);
      return bean;
   }

   // 创建代理
   Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
   if (specificInterceptors != DO_NOT_PROXY) {
      this.advisedBeans.put(cacheKey, Boolean.TRUE);
       //创建代理
      Object proxy = createProxy(
            bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
      this.proxyTypes.put(cacheKey, proxy.getClass());
      return proxy;
   }

   this.advisedBeans.put(cacheKey, Boolean.FALSE);
   return bean;
}
createProxy

通过ProxyFactory创建代理。

protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
      @Nullable Object[] specificInterceptors, TargetSource targetSource) {

   if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
      AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
   }

   ProxyFactory proxyFactory = new ProxyFactory();
   proxyFactory.copyFrom(this);

   if (!proxyFactory.isProxyTargetClass()) {
      if (shouldProxyTargetClass(beanClass, beanName)) {
         proxyFactory.setProxyTargetClass(true);
      }
      else {
         evaluateProxyInterfaces(beanClass, proxyFactory);
      }
   }

   Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
   proxyFactory.addAdvisors(advisors);
   proxyFactory.setTargetSource(targetSource);
   customizeProxyFactory(proxyFactory);

   proxyFactory.setFrozen(this.freezeProxy);
   if (advisorsPreFiltered()) {
      proxyFactory.setPreFiltered(true);
   }

   return proxyFactory.getProxy(getProxyClassLoader());
}
getProxy

createAopProxy来根据当前类创建合适的AOP工厂,即判断使用jdk动态代理还是cglib,分别对应JdkDynamicAopProxyCglibAopProxy

使用对应的AOP工厂完成代理。

public Object getProxy(@Nullable ClassLoader classLoader) {
   return createAopProxy().getProxy(classLoader);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值