Spring如何实现AOP,请不要再说cglib了!

1. 从注解入手找到对应核心类

最近工作中我都是基于注解实现AOP功能,常用的开启AOP的注解是@EnableAspectJAutoProxy,我们就从它入手。


Spring如何实现AOP,请不要再说cglib了!_第1张图片

上面的动图的流程的步骤就是:

@EnableAspectJAutoProxy

--> AspectJAutoProxyRegistrar

-->AopConfigUtils .registerAspectJAnnotationAutoProxyCreatorIfNecessary

-->AnnotationAwareAspectJAutoProxyCreator.class


Spring如何实现AOP,请不要再说cglib了!_第2张图片

虽然找到了核心类,但是并没有找到核心方法!下面我们尝试画类图确定核心方法。

2.画核心类类图,猜测核心方法

AnnotationAwareAspectJAutoProxyCreator的部分类图。

Spring如何实现AOP,请不要再说cglib了!_第3张图片

从类图看到了AnnotationAwareAspectJAutoProxyCreator实现了BeanPostProcessor,而AOP功能应该在创建完Bean之后执行,猜测AnnotationAwareAspectJAutoProxyCreator实现BeanPostProcessor的postProcessAfterInitialization(实例化bean后处理)是核心方法。 查看AnnotationAwareAspectJAutoProxyCreator实现的postProcessAfterInitialization方法,实际该方法在其父类AbstractAutoProxyCreator中。

Spring如何实现AOP,请不要再说cglib了!_第4张图片

发现发现疑似方法wrapIfNecessary,查看其源码如下,发现createProxy方法。确定找对了地方。

Spring如何实现AOP,请不要再说cglib了!_第5张图片

即AnnotationAwareAspectJAutoProxyCreator实现BeanPostProcessor的postProcessAfterInitialization方法,在该方法中由wrapIfNecessary实现了AOP的功能。 wrapIfNecessary中有2个和核心方法

getAdvicesAndAdvisorsForBean获取当前bean匹配的增强器

createProxy为当前bean创建代理

要想明白核心流程还需要分析这2个方法。

3.读重点方法,理核心流程

3.1 getAdvicesAndAdvisorsForBean获取当前bean匹配的增强器

查看源码如下,默认实现在AbstractAdvisorAutoProxyCreator中。

Spring如何实现AOP,请不要再说cglib了!_第6张图片

查阅findEligibleAdvisors方法,就干了3件事

找所有增强器,也就是所有@Aspect注解的Bean

找匹配的增强器,也就是根据@Before,@After等注解上的表达式,与当前bean进行匹配,暴露匹配上的。

对匹配的增强器进行扩展和排序,就是按照@Order或者PriorityOrdered的getOrder的数据值进行排序,越小的越靠前。

Spring如何实现AOP,请不要再说cglib了!_第7张图片

AnnotationAwareAspectJAutoProxyCreator 重写了findCandidateAdvisors,下面我们看看具体实现了什么

3.1.1findCandidateAdvisors找所有增强器,也就是所有@Aspect注解的Bean

Spring如何实现AOP,请不要再说cglib了!_第8张图片

从该方法我们可以看到处理@Aspect注解的bean的方法是:this.aspectJAdvisorsBuilder.buildAspectJAdvisors()。 这个方法如下:

public List buildAspectJAdvisors() {

  List aspectNames = this.aspectBeanNames;

  if (aspectNames == null) {

      synchronized (this) {

        aspectNames = this.aspectBeanNames;

        if (aspectNames == null) {

            List advisors = new ArrayList<>();

            aspectNames = new ArrayList<>();

            //找到所有BeanName            String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(

                  this.beanFactory, Object.class, true, false);

            for (String beanName : beanNames) {

              if (!isEligibleBean(beanName)) {

                  continue;

              }

              // 必须注意,bean会提前暴露,并被Spring容器缓存,但是这时还不能织入。              Class beanType = this.beanFactory.getType(beanName);

              if (beanType == null) {

                  continue;

              }

              if (this.advisorFactory.isAspect(beanType)) {

                  //找到所有被@Aspect注解的类                  aspectNames.add(beanName);

                  AspectMetadata amd = new AspectMetadata(beanType, beanName);

                  if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {

                    MetadataAwareAspectInstanceFactory factory =

                          new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);

                    //解析封装为Advisor返回                    List classAdvisors = this.advisorFactory.getAdvisors(factory);

                    if (this.beanFactory.isSingleton(beanName)) {

                        this.advisorsCache.put(beanName, classAdvisors);

                    }

                    else {

                        this.aspectFactoryCache.put(beanName, factory);

                    }

                    advisors.addAll(classAdvisors);

                  }

                  else {

                    // Per target or per this.                    if (this.beanFactory.isSingleton(beanName)) {

                        throw new IllegalArgumentException("Bean with name '" + beanName +

                              "' is a singleton, but aspect instantiation model is not singleton");

                    }

                    MetadataAwareAspectInstanceFactory factory =

                          new PrototypeAspectInstanceFactory(this.beanFactory, beanName);

                    this.aspectFactoryCache.put(beanName, factory);

                    advisors.addAll(this.advisorFactory.getAdvisors(factory));

                  }

              }

            }

            this.aspectBeanNames = aspectNames;

            return advisors;

        }

      }

  }

  if (aspectNames.isEmpty()) {

      return Collections.emptyList();

  }

  List advisors = new ArrayList<>();

  for (String aspectName : aspectNames) {

      List cachedAdvisors = this.advisorsCache.get(aspectName);

      if (cachedAdvisors != null) {

        advisors.addAll(cachedAdvisors);

      }

      else {

        MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);

        advisors.addAll(this.advisorFactory.getAdvisors(factory));

      }

  }

  return advisors;

}

这个方法可以概括为:

找到所有BeanName

根据BeanName筛选出被@Aspect注解的类

针对类中被Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class注解的方法,先按上边的注解顺序排序后按方法名称排序,每一个方法对应一个Advisor。

3.2 createProxy为当前bean创建代理。

3.2.1 创建代理的2种方式

众所周知,创建代理的常用的2种方式是:JDK创建和CGLIB,下面我们就看看这2中创建代理的例子。

3.2.1 .1 jdk创建代理的例子

Spring如何实现AOP,请不要再说cglib了!_第9张图片

3.2.1 .2 cglib创建代理的例子

Spring如何实现AOP,请不要再说cglib了!_第10张图片

3.2.1 .3 jdk创建代理与cglib创建代理的区别

Spring如何实现AOP,请不要再说cglib了!_第11张图片

3.2.2 Spring如何选择的使用哪种方式

Spring的选择选择如何代理时在DefaultAopProxyFactory 中。

Spring如何实现AOP,请不要再说cglib了!_第12张图片

config.isOptimize() 查看源码注释时发现,这个是配置使用cglib代理时,是否使用积极策略。这个值一般不建议使用!

config.isProxyTargetClass() 就是@EnableAspectJAutoProxy中的proxyTargetClass属性。

hasNoUserSuppliedProxyInterfaces 是否存在可代理的接口

总结下Spring如何选择创建代理的方式:

如果设置了proxyTargetClass=true,一定是CGLIB代理

如果proxyTargetClass=false,目标对象实现了接口,走JDK代理

如果没有实现接口,走CGLIB代理

4.总结

Spring如何实现AOP?,您可以这样说:

AnnotationAwareAspectJAutoProxyCreator是AOP核心处理类

AnnotationAwareAspectJAutoProxyCreator实现了BeanProcessor,其中postProcessAfterInitialization是核心方法。

核心实现分为2步

getAdvicesAndAdvisorsForBean获取当前bean匹配的增强器 createProxy为当前bean创建代理

getAdvicesAndAdvisorsForBean核心逻辑如下

a. 找所有增强器,也就是所有@Aspect注解的Bean

b. 找匹配的增强器,也就是根据@Before,@After等注解上的表达式,与当前bean进行匹配,暴露匹配上的。

c. 对匹配的增强器进行扩展和排序,就是按照@Order或者PriorityOrdered的getOrder的数据值进行排序,越小的越靠前。

createProxy有2种创建方法,JDK代理或CGLIB

a. 如果设置了proxyTargetClass=true,一定是CGLIB代理

b. 如果proxyTargetClass=false,目标对象实现了接口,走JDK代理

c. 如果没有实现接口,走CGLIB代理


本次给大家分享一些学习资料,里面包括:(高可用、高并发、高性能及分布式、Jvm性能调优、Spring源码,MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多个知识点的架构资料)以及Java进阶学习路线图,添加VX:19821111174 【验证】即可免费获取:最后,祝大家早日学有所成!

你可能感兴趣的:(Spring如何实现AOP,请不要再说cglib了!)