深入理解spring-AOP注解的底层实现原理

Posted 一个懒惰的程序员

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了深入理解spring-AOP注解的底层实现原理相关的知识,希望对你有一定的参考价值。

上文简单的介绍了一下基于注解的spring-AOP的使用,没有看过的童鞋可以点击查看,接下来我们就来看看它的底层实现原理是怎样的?


首先我们从开启切面注解@EnableAspectJAutoProxy入手,进去之后可以发现它import()了一个组件AspectJAutoProxyRegistrar如下:



@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {

   /**
    * Indicate whether subclass-based (CGLIB) proxies are to be created as opposed
    * to standard Java interface-based proxies. The default is {@code false}.
    */

   boolean proxyTargetClass() default false;

   /**
    * Indicate that the proxy should be exposed by the AOP framework as a {@code ThreadLocal}
    * for retrieval via the {@link org.springframework.aop.framework.AopContext} class.
    * Off by default, i.e. no guarantees that {@code AopContext} access will work.
    * @since 4.3.1
    */

   boolean exposeProxy() default false;

}


继续进入AspectJAutoProxyRegistrar我们可以发现它实现了ImportBeanDefinitionRegistrar接口,里边就一个方法registerBeanDefinitions如下:



public void registerBeanDefinitions(
           AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry)
{

       AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);

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


到这里我们可以发现AspectJAutoProxyRegistrar就是自定义封装去注册bean,注意其中的AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry)这行代码,进去我们可以发现注册的是一个AspectJAwareAdvisorAutoProxyCreator如下:


public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) {
       return registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry, null);
}

public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, Object source) {
       return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}


一直跟踪AspectJAwareAdvisorAutoProxyCreator进去查看其继承关系如下:


AspectJAwareAdvisorAutoProxyCreator
    -->extends AbstractAdvisorAutoProxyCreator
        -->extends AbstractAutoProxyCreator
            -->extends ProxyProcessorSupport implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware

重点看其中标红的两个类,从名字我们可以发现是不是符合xxxBeanPostProcessor和xxxAware,看过小编之前的文章的童鞋应该比较清楚了,没有看过的可以点击以下连接查看:


这边再简单总结下其启动处理流程如下:

1、传入配置类,创建基于注解的ioc容器AnnotationConfigApplicationContext

2、注册配置类,调用refresh方法刷新容器;

3、registerBeanPostProcessors(beanFactory)注册bean的后置处理器来拦截bean的创建;

  • 1)、先获取ioc容器已经定义了的需要创建对象的所有BeanPostProcessor

  • 2)、给容器中加别的BeanPostProcessor

  • 3)、优先注册实现了PriorityOrdered接口的BeanPostProcessor;

  • 4)、再给容器中注册实现了Ordered接口的BeanPostProcessor;

  • 5)、注册没实现优先级接口的BeanPostProcessor;

  • 6)、注册BeanPostProcessor,实际上就是创建对应的bean对象注册到容器中;

    • 1)、创建Bean的实例

    • 2)、populateBean;给bean的各种属性赋值

    • 3)、initializeBean:初始化bean;

      • 1)、invokeAwareMethods()处理Aware接口的方法回调

      • 2)、applyBeanPostProcessorsBeforeInitialization()应用后置处理器的postProcessBeforeInitialization()

      • 3)、invokeInitMethods();执行自定义的初始化方法

      • 4)、applyBeanPostProcessorsAfterInitialization()执行后置处理器的postProcessAfterInitialization();

  • 7)、把BeanPostProcessor注册到BeanFactory中beanFactory.addBeanPostProcessor(postProcessor);

以上就是注册和创建BeanPostProcessor的主要流程自然也就是创建AnnotationAwareAspectJAutoProxyCreator的流程了,接下来再来看看针对AOP切面在AnnotationAwareAspectJAutoProxyCreator中是如何处理的,进入到InstantiationAwareBeanPostProcessor接口的实现postProcessBeforeInstantiation方法如下:


@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
       Object cacheKey = getCacheKey(beanClass, beanName);

       if (beanName == null || !this.targetSourcedBeans.contains(beanName)) {
           if (this.advisedBeans.containsKey(cacheKey)) {
               return null;
           }
           if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
               this.advisedBeans.put(cacheKey, Boolean.FALSE);
               return null;
           }
       }

       // Create proxy here if we have a custom TargetSource.
       // Suppresses unnecessary default instantiation of the target bean:
       // The TargetSource will handle target instances in a custom fashion.
       if (beanName != null) {
           TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
           if (targetSource != null) {
               this.targetSourcedBeans.add(beanName);
               Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
               Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
               this.proxyTypes.put(cacheKey, proxy.getClass());
               return proxy;
           }
       }

       return null;
}


找到isInfrastructureClass方法判断当前类是否是基础类Advice,Pointcut,Advisor,AopInfrastructureBean以及是否是切面类是否包含@Aspect注解),接下来进入getAdvicesAndAdvisorsForBean获取对应的拦截器链如下:


protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, TargetSource targetSource) {
       List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
       if (advisors.isEmpty()) {
           return DO_NOT_PROXY;
       }
       return advisors.toArray();
}


/**
    * Find all eligible Advisors for auto-proxying this class.
    * @param beanClass the clazz to find advisors for
    * @param beanName the name of the currently proxied bean
    * @return the empty List, not {@code null},
    * if there are no pointcuts or interceptors
    * @see #findCandidateAdvisors
    * @see #sortAdvisors
    * @see #extendAdvisors
    */

   protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
       List<Advisor> candidateAdvisors = findCandidateAdvisors();
       List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
       extendAdvisors(eligibleAdvisors);
       if (!eligibleAdvisors.isEmpty()) {
           eligibleAdvisors = sortAdvisors(eligibleAdvisors);
       }
       return eligibleAdvisors;
}


最后一步也是最关键的一步创建对应的AOP动态代理createProxy如下:


protected Object createProxy(
           Class<?> beanClass, String beanName, 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如下:


public Object getProxy(ClassLoader classLoader) {
       return createAopProxy().getProxy(classLoader);
}


再一直跟进到createAopProxy的实现如下:


public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
       if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
           Class<?> targetClass = config.getTargetClass();
           if (targetClass == null) {
               throw new AopConfigException("TargetSource cannot determine target class: " +
                       "Either an interface or a target is required for proxy creation.");
           }
           if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
               return new JdkDynamicAopProxy(config);
           }
          // 基于cglib的动态代理
           return new ObjenesisCglibAopProxy(config);
       }
       else {
           // jdk动态代理
           return new JdkDynamicAopProxy(config);
       }
}


发现没spring会根据对应的判断采用不同的动态代理的实现,可以是cglib对应的实现也可以基于jdk自己的动态代理实现,有关动态代理的实现原理可以查看



继续进入到CglibAopProxy的动态代理类中的内部静态类的intercept方法如下:


@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
           Object oldProxy = null;
           boolean setProxyContext = false;
           Class<?> targetClass = null;
           Object target = null;
           try {
               // 省略部分代码....
                               // 取将要执行的目标方法拦截器链
               List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
               Object retVal;
               // Check whether we only have one InvokerInterceptor: that is,
               // no real advice, but just reflective invocation of the target.
              // 如果没有拦截器链则直接执行目标方法
               if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
                   // We can skip creating a MethodInvocation: just invoke the target directly.
                   // Note that the final invoker must be an InvokerInterceptor, so we know
                   // it does nothing but a reflective operation on the target, and no hot
                   // swapping or fancy proxying.
                   Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
                   retVal = methodProxy.invoke(target, argsToUse);
               }
               else {
                   // We need to create a method invocation...
                   retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
               }
               retVal = processReturnType(proxy, target, method, retVal);
               return retVal;
           }
           finally {
               if (target != null) {
                   releaseTarget(target);
               }
               if (setProxyContext) {
                   // Restore old proxy.
                   AopContext.setCurrentProxy(oldProxy);
               }
           }
}


根据ProxyFactory对象获取将要执行的目标方法拦截器链List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice,再遍历获取到的拦截器链执行拦截方法如下:


public Object proceed() throws Throwable {
       //  We start with an index of -1 and increment early.
       if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
           return invokeJoinpoint();
       }

       Object interceptorOrInterceptionAdvice =
               this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
       if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
           // Evaluate dynamic method matcher here: static part will already have
           // been evaluated and found to match.
           InterceptorAndDynamicMethodMatcher dm =
                   (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
           if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
               return dm.interceptor.invoke(this);
           }
           else {
               // Dynamic matching failed.
               // Skip this interceptor and invoke the next in the chain.
               return proceed();
           }
       }
       else {
           // It's an interceptor, so we just invoke it: The pointcut will have
           // been evaluated statically before this object was constructed.
           return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
       }
}


好了,到此springAOP的实现原理到这里就全部介绍完了,对springAOP具体实现机制感兴趣的同学建议根据这个流程去看一遍,下边再稍微简单总结下AOP分析的大致流程如下:

1) @EnableAspectJAutoProxy 开启AOP功能
2)、 @EnableAspectJAutoProxy 往容器中注册一个组件              AnnotationAwareAspectJAutoProxyCreator
3)、AnnotationAwareAspectJAutoProxyCreator是一个后置处理器BeanPostProcessor;
4)、容器的创建流程:

  • 1)、registerBeanPostProcessors注册后置处理器,创建AnnotationAwareAspectJAutoProxyCreator对象

  • 2)、finishBeanFactoryInitialization初始化剩下的单实例bean

    • 1)、创建业务逻辑组件和切面组件

    • 2)、AnnotationAwareAspectJAutoProxyCreator拦截组件的创建过程

    • 3)、组件创建完之后,判断组件是否需要增强

    • 如果是:则把切面的通知方法包装成增强器(Advisor),再给业务组件创建一个代理对象(cglib);

5)、执行目标方法

  • 1)、代理对象执行目标方法

  • 2)、CglibAopProxy.intercept();

  • 1)、得到目标方法的拦截器链(增强器包装成拦截器MethodInterceptor)

  • 2)、利用拦截器的链式机制,依次进入每一个拦截器进行执行;

  • 3)、结果:

    • 正常执行:前置通知-》目标方法-》后置通知-》返回通知

    • 出现异常:前置通知-》目标方法-》后置通知-》异常通知

以上是今天文章的所有内容,欢迎大家吐槽


推荐阅读



以上是关于深入理解spring-AOP注解的底层实现原理的主要内容,如果未能解决你的问题,请参考以下文章

spring-AOP原理

深入理解Java 注解原理

深入理解AbstractQueuedSynchronizerReentrantLock底层实现原理

深入理解Tomcat

深入理解Java中的底层阻塞原理及实现

深入理解 Mysql 索引底层原理