5.2 spring5源码--spring AOP源码分析三---切面源码分析

5.2 spring5源码--spring AOP源码分析三---切面源码分析,第1张

概述一. AOP切面源码分析 源码分析分为三部分 1. 解析切面 2. 创建动态代理 3. 调用 源码的入口 源码分析的入口, 从注解开始: 组件的入口是一个注解, 比如启用AOP的注解@EnableAs 一. AOP切面源码分析

源码分析分为三部分

1. 解析切面2. 创建动态代理3. 调用

 

源码的入口
源码分析的入口,从注解开始:组件的入口是一个注解,比如启用AOP的注解@EnableAspectJAutoproxy. 在注解的实现类里面,会有一个@import(""). 这个@import("")就是引入的源码实现类. 比如AOP的@import(AspectJAutoproxyRegistrar.class)
通常,Spring要开启某一个功能,都会增加一个注解,如果我们再想要看某一个功能的源码,那么就可以从他的注解跟进去看,在找到@import("")就找到源码的入口了

源码分析的入口,AOP注解:

package com.lxl.www.aop;import org.springframework.beans.factory.annotation.Configurable;import org.springframework.context.annotation.ComponentScan;import org.springframework.context.annotation.EnableAspectJAutoproxy;@Configurable// 使用注解的方式引入AOP@EnableAspectJAutoproxy@ComponentScan("com.lxl.www.aop")public class MainConfig {}

引入AOP,我们需要在配置文件中增加@EnableAspectJAutoproxy代理. 那么想要去掉AOP的引入,只需要将这个注解注释掉就可以了.  这个注解解释整个AOP的入口. 

提示: 其他组件的引入也是类似的,通常引入组件,需要增加一个注解,而整个功能的入口就在这个主机上面.

接下来,进入到注解类

package org.springframework.context.annotation;import java.lang.annotation.documented;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@documented@import(AspectJAutoproxyRegistrar.class)public @interface EnableAspectJAutoproxy {    boolean proxyTargetClass() default false;    boolean exposeProxy() ;}

 

这是,我们看到EnableAspectJAutoproxy类增加了一个@import注解类,我们知道import注解可以向IoC容器中增加一个bean.

 

下面进入到AspectJAutoproxyRegistrar类

 

package org.springframework.context.annotation;import org.springframework.aop.config.AopConfigUtils;import org.springframework.beans.factory.support.BeanDeFinitionRegistry;import org.springframework.core.annotation.AnnotationAttributes;import org.springframework.core.type.AnnotationMetadata;class AspectJAutoproxyRegistrar implements importBeanDeFinitionRegistrar {    /**     * Register,escalate,and configure the AspectJ auto proxy creator based on the value     * of the @{@link EnableAspectJAutoproxy#proxyTargetClass()} attribute on the importing     * {@code @Configuration} class.     */    @OverrIDe    public voID registerBeanDeFinitions(            AnnotationMetadata importingClassMetadata,BeanDeFinitionRegistry registry) {            AopConfigUtils.registeraspectJAnnotationAutoproxyCreatorIfNecessary(registry);        AnnotationAttributes enableAspectJAutoproxy =                AnnotationConfigUtils.attributesFor(importingClassMetadata,EnableAspectJAutoproxy.);        if (enableAspectJAutoproxy != null) {            if (enableAspectJAutoproxy.getBoolean("proxyTargetClass")) {                AopConfigUtils.forceAutoproxyCreatorToUseClassproxying(registry);            }            exposeProxy)) {                AopConfigUtils.forceAutoproxyCreatorToExposeProxy(registry);            }        }    }}

 

我们看到,使用importBeanDeFinitionRegistrar注册了一个BeanDeFinition.

需要记住的是,通常使用importBeanDeFinitionRegistrar结合@import可以向容器中注册一个BeanDeFinition.

如何注册的呢? 看具体实现. 

AopConfigUtils.registeraspectJAnnotationAutoproxyCreatorIfNecessary(registry);

 注册名字是internalAutoproxyCreator的AnnotationAwareAspectJAutoproxyCreator

@Nullable    static BeanDeFinition registeraspectJAnnotationAutoproxyCreatorIfNecessary(            BeanDeFinitionRegistry registry,@Nullable Object source) {        *         * 注册一个AnnotationAwareAspectJAutoproxyCreator类型的bean定义         */        return registerOrEscalateApcAsrequired(AnnotationAwareAspectJAutoproxyCreator.,registry,source);    }

 

如上结构梳理如下: 

 

我们看到,  注册了类AnnotationAwareAspectJAutoproxyCreator类型的bean. 这是一个什么样的类呢? 我们来看一下类的结构. 这个类的继承结构很庞大,我们只看和本次内容相关的继承结构

解析切面,创建动态代理,都是在bean的后置处理器中进行的,下面对照着AOP的实现原理以及createBean(创建bean)的过程来看

 

上图是bean加载过程中调用的9次后置处理器. 在创建bean之前调用了InstantiationAwareBeanPostProcessor后置处理器判断是否需要为这个类创建AOP,也就是解析切面的过程. 所以在AnnotationAwareAspectJAutoproxyCreator里面实现了InstantiationAwareBeanPostProcessor后置处理器的接口. 重写了postProcessBeforeInstantiation方法. 

在createBean的第三阶段初始化之后,要创建AOP的动态代理,调用了BeanPostProcess后置处理器, AnnotationAwareAspectJAutoproxyCreator也实现了BeanPostProcess接口. 重写了postProcessAfterInitialization. 

同时也需要处理AOP的循环依赖的问题,处理循环依赖是在属性赋值之前调用SmartInstantiationAwareBeanPostProcessor后置处理器,然后重写getEarlyBeanReference方法. 我们看到AnnotationAwareAspectJAutoproxyCreator也实现了SmartInstantiationAwareBeanPostProcessor接口. 并重写getEarlyBeanReference方法.

 

1) AOP解析切面 

 

 通过上面的分析,我们知道了,解析切面是在重写了InstantiationAwareBeanPostProcessor后置处理器的postProcessBeforeInstantiation方法. 所以,我们要找到AnnotationAwareAspectJAutoproxyCreator重写的postProcessBeforeInstantiation方法.

小贴士如何找到呢? 在IDea中使用快捷键ctrl + o,找到当前类重写的所有方法. 在搜索postProcessBeforeInstantiation,就可以找到了

 进入创建动态代理的bean的后置处理器,这是解析切面的第一个入口

@OverrIDe    public Object postProcessBeforeInstantiation(Class<?> beanClass,String beanname) {        ......    }

我们在postProcessBeforeInstantiation方法的入口处打一个断点,  接下来看一下这个接口的调用链

 

 如上图,可以看出我们的入口是main方法,然后调用了refresh()方法,执行的是refresh()方法的finishbeanfactoryInitialization()方法,然胡调用了doGetBean()下的createBean().然后调用的是resolveBeforeInstantiation的applyBeanPostProcessorsBeforeInstantiation方法,在这里获取到所有的bean的后置处理器,判断这个bean的后置处理器是否是InstantiationAwareBeanPostProcessor的一个实例. 如果是,那么就调用postProcessBeforeInstantiation()方法. 

protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass,String beanname) {        *         * 获取容器中所有的后置处理器         * 这之前有一个注册bean定义的方法,已经注册过了. 所以在这里可以获取到列表         *         * 9次bean的后置处理器,都是一个类实现InstantiationAwareBeanPostProcessor类,重写postProcessBeforeInstantiation方法         for (BeanPostProcessor bp : getBeanPostProcessors()) {            if (bp instanceof InstantiationAwareBeanPostProcessor) {                InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;                Object result = ibp.postProcessBeforeInstantiation(beanClass,beanname);                if (result != ) {                    return result;                }            }        }        return ;    }

 

下面就来分析postProcessBeforeInstantiation()方法

@OverrIDe    public Object postProcessBeforeInstantiation(Class<?>*         * 在第一个bean创建的时候,就会去调用所有的bean的后置处理器,并且解析所有的切面.         * 这一步是非常消耗性能的. 所以,会放到缓存当中         // 构建缓存的key        Object cacheKey = getCacheKey(beanClass,beanname);         没有beanname或者不包含在targetSourcedBeans        if (!StringUtils.hasLength(beanname) || !this.targetSourcedBeans.contains(beanname)) {             判断是否已经被解析过?            if (.advisedBeans.containsKey(cacheKey)) {                 解析过,则直接返回                ;            }                         * 判断当前这个类是不是需要跳过的类.如果是基础类或者是应该跳过里的类,则返回null,表示这个类不需要被解析             *             * 判断是不是基础bean(是不是切面类,通知,切点). 因为如果类本身是一个通知,切面,那我们不需要解析它             * 跳过的类: 默认是false. 在shouldSkip里面拿到所有的bean定义,标记是不是@Aspect,然后将每一个通知生成一个advisor             */            if (isInfrastructureClass(beanClass) || shouldSkip(beanClass,beanname)) {                *                 * advisedBean是一个集合,用来保存类是否是一个advise                 */                .advisedBeans.put(cacheKey,Boolean.FALSE);                ;            }        }         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.        TargetSource targetSource = getCustomTargetSource(beanClass,beanname);        if (targetSource !=  (StringUtils.hasLength(beanname)) {                .targetSourcedBeans.add(beanname);            }            Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass,beanname,targetSource);             创建了代理            Object proxy = createProxy(beanClass,specificInterceptors,targetSource);            .proxyTypes.put(cacheKey,proxy.getClass());             proxy;        }        ;    }

第一步: 构建缓存

构建缓存的keyObject cacheKey = getCacheKey(beanClass,beanname);
在第一个bean创建的时候,并且解析所有的切面.
这一步是非常消耗性能的. 所以,会放到缓存当中. 已经创建过的,后面将不再创建

第二步: 校验bean是否被解析过. 如果已经解析过,则不再解析

 判断是否已经被解析过.advisedBeans.containsKey(cacheKey)) {    ;}  

第三步: 判断类是否是需要跳过的类

*     * advisedBean是一个集合,用来保存类是否是一个advise     */    ;}

 如果是基础类或者是应该跳过的类,表示这个类不需要被解析.

 这里有两个判断.

isInfrastructureClass(beanClass) 判断当前这个类是不是基础类,这里的基础类的含义如下: Advice、pointcut、Advisor、AopInfrastructureBean。如果本身就是基础类,那么不用在解析了

protected boolean isInfrastructureClass(Class<?> beanClass) {         如果这个类是一个Advice类型的类,或者 pointcut类型的类,或者Adivsor类型的类,或者AOPInsfrastructureBean类型的类.        boolean retVal = Advice.class.isAssignableFrom(beanClass) ||                pointcut.                Advisor.                AopInfrastructureBean..isAssignableFrom(beanClass);        if (retVal && logger.isTraceEnabled()) {            logger.trace(DID not attempt to auto-proxy infrastructure class [" + beanClass.getname() + ]);        }         retVal;    }

 

shouldSkip(beanClass,beanname)判断当前是否是需要跳过的类 .

protected boolean shouldSkip(Class<?> 找到候选的Advisors(前置通知,后置通知等)        List<Advisor> candIDateAdvisors = findCandIDateAdvisors();         (Advisor advisor : candIDateAdvisors) {            if (advisor instanceof AspectJpointcutAdvisor &&                    ((AspectJpointcutAdvisor) advisor).getAspectname().equals(beanname)) {                true;            }        }         super.shouldSkip(beanClass,beanname);    }

 

findCandIDateAdvisors(); 找到候选的类,然后将候选类构造成Advisor对象. 进到方法里看看是如何筛选出候选对象的. 

AnnotationAwareAspectJAutoproxyCreator.findCandIDateAdvisors()

protected List<Advisor> findCandIDateAdvisors() {         Add all the Spring advisors found according to superclass rules.         找到xml方式配置的Advisor和原生接口的AOP的advisor 以及找到事务相关的advisor        List<Advisor> advisors = super.findCandIDateAdvisors();         Build Advisors for all AspectJ aspects in the bean factory.         将找到的aspect,封装为一个Advisor        this.aspectJAdvisorsBuilder != buildAspectJAdvisors()方法就是用来解析切面类,判断是否含有@Aspect注解,然后将每一个通知生成一个advisor            advisors.addAll(.aspectJAdvisorsBuilder.buildAspectJAdvisors());        }         返回所有的通知         advisors;    }

 

这里做了两件事

第一步: 解析xml方式配置的Advisor (包括原生接口方式配置的advisor 以及找到事务相关的advisor)

第二步: 解析注解方式的切面. buildAspectJAdvisors()方法是用来解析切面类的. 解析每一个切面类中的通知方法, 并为每个方法匹配切点表达式.

 

public List<Advisor> buildAspectJAdvisors() {         * aspectnames: 用于保存切面名称的集合     * aspectnames是缓存的类级别的切面,缓存的是已经解析出来的切面信息         List<String> aspectnames = .aspectBeannames;     如果aspectnames值为空,那么就在第一个单例bean执行的时候调用后置处理器(AnnotationAwareAspectJAutoproxy)    if (aspectnames == ) {       加锁,防止多个线程,同时加载 Aspect      synchronized () {        aspectnames = .aspectBeannames;         双重检查        ) {           保存所有从切面中解析出来的通知          List<Advisor> advisors = new ArrayList<>();           保存切面名称的集合          aspectnames =            * 扫描Object的子类. 那就是扫描所有的类           *           * 这里传入要扫描的对象是Object.class. 也就是说去容器中扫描所有的类.           * 循环遍历. 这个过程是非常耗性能的,所以spring增加了缓存来保存切面           *           * 但事务功能除外,事务模块是直接去容器中找到Advisor类型的类 选择范围小           * spring 没有给事务模块加缓存           */          String[] beannames = beanfactoryUtils.beannamesForTypeIncludingAncestors(              this.beanfactory, Object.class,true,1)">);           循环遍历beannames           (String beanname : beannames) {            if (!isEligibleBean(beanname)) {              continue We must be careful not to instantiate beans eagerly as in this case they             would be cached by the Spring container but would not have been weaved.             通过beanname去容器中获取到对应class对象            Class<?> beanType = .beanfactory.getType(beanname);            if (beanType == ) {               判断bean是否是一个切面,也就是脑袋上是否有@Aspect注解            this.advisorFactory.isAspect(beanType)) {              aspectnames.add(beanname);               将beanname和class对象构建成一个AspectMetadata对象              AspectMetadata amd = new AspectMetadata(beanType,beanname);              if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLetoN) {                MetadataAwareAspectInstanceFactory factory =                    new beanfactoryAspectInstanceFactory(.beanfactory,1)"> 解析切面类中所有的通知--一个通知生成一个Advisor.                List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);                 加入到缓存中                .beanfactory.isSingleton(beanname)) {                  .advisorsCache.put(beanname,classAdvisors);                } else {                  .aspectFactoryCache.put(beanname,factory);                }                advisors.addAll(classAdvisors);              }  {                 Per target or per this.                throw new IllegalArgumentException(Bean with name '" + beanname +                      ' is a singleton,but aspect instantiation model is not singleton);                }                MetadataAwareAspectInstanceFactory factory =                    new PrototypeAspectInstanceFactory(.advisorFactory.getAdvisors(factory));              }            }          }          this.aspectBeannames = aspectnames;           advisors;        }      }    }     (aspectnames.isEmpty()) {       Collections.emptyList();    }    List<Advisor> advisors = ();     (String aspectname : aspectnames) {      List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectname);      if (cachedAdvisors != ) {        advisors.addAll(cachedAdvisors);      }  {        MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.(aspectname);        advisors.addAll(.advisorFactory.getAdvisors(factory));      }    }     advisors;  }

 

我们来看看如何生成List<Advisor>的

 解析切面类中所有的通知--一个通知生成一个Advisor.List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
 getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {         获取标记了@Aspect的类        Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();         获取切面类的名称        String aspectname = aspectInstanceFactory.getAspectMetadata().getAspectname();         验证切面类        valIDate(aspectClass);         We need to wrap the MetadataAwareAspectInstanceFactory with a decorator         so that it will only instantiate once.         使用包装的模式来包装 aspectInstanceFactory,构建成MetadataAwareAspectInstanceFactory类        MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =                 LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);         通知的集合,按照排序后        List<Advisor> advisors = ();         获取切面类中所有的通知方法,除了带有@pointcut注解的方法         (Method method : getAdvisorMethods(aspectClass)) {             将候选方法解析为Advisor. Advisor中包含advise和pointcut. 注意: getAdvisor()方法中定义了切面解析的顺序            Advisor advisor = getAdvisor(method,lazySingletonAspectInstanceFactory,aspectname);            if (advisor != ) {                advisors.add(advisor);            }        }         If it's a per target aspect,emit the dummy instantiating aspect.        if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {            Advisor instantiationAdvisor =  SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);            advisors.add(0 Find introduction fIElds.         (FIEld fIEld : aspectClass.getDeclaredFIElds()) {            Advisor advisor = getDeclareParentsAdvisor(fIEld);             advisors;    }

 

这里主要有两点,第一个是getAdvisorMethods(aspectClass)获取当前切面类的所有的AdvisorMethod,第二个是封装成的Advisor对象

第一步: 解析切面类中所有的通知方法.getAdvisorMethods(aspectClass)
*     * 获取切面类中所有的方法,且方法中有@pointcut注解     * @param aspectClass     * @return     private List<Method> getAdvisorMethods(Class<?> aspectClass) {        final List<Method> methods =  调用doWithMethods. 第二个参数是一个匿名函数,重写了doWith方法        ReflectionUtils.doWithMethods(aspectClass,method -> {             解析切面类中所有的方法,除了pointcut            if (AnnotationUtils.getAnnotation(method,pointcut.class) == null) {                methods.add(method);            }        },ReflectionUtils.USER_DECLARED_METHODS);        if (methods.size() > 1) {            // 对方法进行排序            methods.sort(METHOD_COMParaTOR);        }         methods;    }

 

这个方法是,扫描切面类的所有方法,将其添加到methods中,除了pointcut注解的方法

然后对methods进行排序,如何排序呢?

private static final Comparator<Method> METHOD_COMParaTOR;     {        Comparator<Method> adviceKindComparator = new ConvertingComparator<>(                new InstanceComparator<>(                        Around.class,Before.class),(Converter<Method,Annotation>) method -> {                    AspectJAnnotation<?> ann = AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(method);                    return (ann != null ? ann.getAnnotation() : );                });        Comparator<Method> methodnameComparator = (Method::getname);        METHOD_COMParaTOR = adviceKindComparator.thenComparing(methodnameComparator);    }

 

按照Aroud,Before,After,Aferreturning,AfterThrowing的顺序对通知方法进行排序

第二步: 将候选的方法解析为Advisor. 这里也是有两步.具体如下:
*     * 解析切面类中的方法     * @param candIDateAdviceMethod 候选的方法         @OverrIDe    @Nullable     Advisor getAdvisor(Method candIDateAdviceMethod,MetadataAwareAspectInstanceFactory aspectInstanceFactory,int declarationorderInAspect,String aspectname) {        valIDate(aspectInstanceFactory.getAspectMetadata().getAspectClass());         获取切面中候选方法的切点表达式        AspectJExpressionpointcut Expressionpointcut = getpointcut(                candIDateAdviceMethod,aspectInstanceFactory.getAspectMetadata().getAspectClass());        if (Expressionpointcut == ;        }         将切点表达式和通知封装到InstantiationModelAwarepointcutAdvisorImpl对象中,这是一个Advisor通知         InstantiationModelAwarepointcutAdvisorImpl(Expressionpointcut,candIDateAdviceMethod,aspectInstanceFactory,declarationorderInAspect,aspectname);    }

 

在getpointcut中解析了method,以及切点表达式pointcut

*     * 找到候选方法method属于哪一种类型的Aspectj通知     * @param candIDateAdviceMethod        候选的通知方法     * @param candIDateAspectClass        候选的切面类     * @return         @Nullable    private AspectJExpressionpointcut getpointcut(Method candIDateAdviceMethod,Class<?> candIDateAspectClass) {        // 第一步: 解析候选方法上的注解,类似@Before(value="pointcut()")         找到Aspectj注解:  @pointcut,@Around,@Before,@After,@AfterReturning,@AfterThrowing        AspectJAnnotation<?> aspectJAnnotation =                AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candIDateAdviceMethod);        if (aspectJAnnotation ==  第二步: 解析aspect切面中的切点表达式        AspectJExpressionpointcut ajexp =                new AspectJExpressionpointcut(candIDateAspectClass,1)">new String[0],1)">new Class<?>[]);         解析切点表达式        ajexp.setExpression(aspectJAnnotation.getpointcutExpression());        this.beanfactory != ) {            ajexp.setbeanfactory(.beanfactory);        }         ajexp;    }

 

如上代码,可知,这里也是有两个 *** 作. 分别是将method解析为Advise,另一个是解析切面类中的pointcut切点表达式. 返回返回切点表达式.

接下来,就是将候选方法和切点表达式封装成Advisor. 在getAdvisor(...)方法中:

// 将切点表达式和通知封装到InstantiationModelAwarepointcutAdvisorImpl对象中,这是一个Advisor通知return new InstantiationModelAwarepointcutAdvisorImpl(Expressionpointcut,candIDateAdviceMethod,this,aspectname);

 

Expressionpointcut: 即切点表达式; candIDateAdviceMethod: 即候选方法

 InstantiationModelAwarepointcutAdvisorImpl(AspectJExpressionpointcut declaredpointcut,Method aspectJAdviceMethod,AspectJAdvisorFactory aspectJAdvisorFactory,1)"> declarationorder,String aspectname) {         当前的切点        this.declaredpointcut = declaredpointcut;         切面类        this.declaringClass = aspectJAdviceMethod.getDeclaringClass();         切面方法名        this.methodname = aspectJAdviceMethod.getname();        切面方法参数的类型        this.parameterTypes = aspectJAdviceMethod.getParameterTypes();        切面方法对象        this.aspectJAdviceMethod = aspectJAdviceMethod;         aspectJ的通知工厂        this.aspectJAdvisorFactory = aspectJAdvisorFactory;         aspectJ的实例工厂        this.aspectInstanceFactory = aspectInstanceFactory;         advisor的顺序        *         * 前面我们看到,Advisor会进行排序,Around,AfterReturning,AfterThrowing,按照这个顺序.         * 那么order值是什么呢?是advisors的size. 如果size是0,那么就是第一个方法. 这里第一个不一定是Around,他可能没有Around通知,也没有Before通知.         this.declarationorder = declarationorder;         切面名        this.aspectname = aspectname;         (aspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {             Static part of the pointcut is a lazy type.            pointcut preInstantiationpointcut = pointcuts.union(                    aspectInstanceFactory.getAspectMetadata().getPerClausepointcut(),1)">.declaredpointcut);                        this.pointcut =  PerTargetInstantiationModelpointcut(                    .declaredpointcut,preInstantiationpointcut,aspectInstanceFactory);            this.lazy = ;        }         A singleton aspect.            .declaredpointcut;            ;            this.instantiatedAdvice = instantiateAdvice(this.declaredpointcut);        }    }

 

前面已经得到了切入点表达式,这里会进行初始化Advice,初始化的时候,根据通知的类型进行初始化.

环绕通知,构建一个环绕通知的对象前置通知,构建一个前置通知的对象后置通知,构建一个后置通知的对象异常通知,构建一个异常通知的对象返回通知,构建一个返回通知的对象

具体代码如下: 

@OverrIDe    @Nullable     Advice getAdvice(Method candIDateAdviceMethod,AspectJExpressionpointcut Expressionpointcut,String aspectname) {         候选的切面类        Class<?> candIDateAspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();        valIDate(candIDateAspectClass);         通知方法上的注解内容        AspectJAnnotation<?> aspectJAnnotation = If we get here,we kNow we have an AspectJ method.         Check that it's an AspectJ-annotated class        isAspect(candIDateAspectClass)) {            new AopConfigException(Advice must be declared insIDe an aspect type: " +                    Offending method '" + candIDateAdviceMethod + ' in class [" +                    candIDateAspectClass.getname() + );        }         (logger.isDeBUGEnabled()) {            logger.deBUG(Found AspectJ method:  candIDateAdviceMethod);        }        AbstractAspectJAdvice springAdvice;        switch (aspectJAnnotation.getAnnotationType()) {            case Atpointcut:                 (logger.isDeBUGEnabled()) {                    logger.deBUG(Processing pointcut '" + candIDateAdviceMethod.getname() + ');                }                ;             ATaround:                 封装成环绕通知的对象                springAdvice =  AspectJAroundAdvice(                        candIDateAdviceMethod,Expressionpointcut,aspectInstanceFactory);                break AtBefore:                 封装成前置通知对象                springAdvice =  AspectJMethodBeforeAdvice(                        candIDateAdviceMethod,1)"> AtAfter:                 封装成后置通知对象                springAdvice =  AspectJAfteradvice(                        candIDateAdviceMethod,1)"> AtAfterReturning:                 封装成返回通知对象                springAdvice =  AspectJAfterReturningAdvice(                        candIDateAdviceMethod,aspectInstanceFactory);                AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();                 (StringUtils.hasText(afterReturningAnnotation.returning())) {                    springAdvice.setReturningname(afterReturningAnnotation.returning());                }                 AtAfterThrowing:                 封装异常通知对象                springAdvice =  AspectJAfterThrowingAdvice(                        candIDateAdviceMethod,aspectInstanceFactory);                AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();                 (StringUtils.hasText(afterThrowingAnnotation.throwing())) {                    springAdvice.setThrowingname(afterThrowingAnnotation.throwing());                }                default:                 UnsupportedOperationException(                        Unsupported advice type on method:  candIDateAdviceMethod);        }         Now to configure the advice...        springAdvice.setAspectname(aspectname);        springAdvice.setDeclarationorder(declarationorder);        String[] argnames = .parameternamediscoverer.getParameternames(candIDateAdviceMethod);        if (argnames != ) {            springAdvice.setArgumentnamesFromStringArray(argnames);        }        springAdvice.calculateArgumentBindings();         springAdvice;    }

 

这就是我们在之前的结构中说过的,在解析切面的时候,会解析切面中的每一个方法,将其解析成一个Advisor,而每一个Advisor都包含两个部分:Advise和pointcut.

最后,将所有的切面类都解析完,将所有的Advisor放入到集合advisors中返回.

 

这样就完成了切面的解析.

 

2) 调用动态代理

在ioc解析的过程中,是在什么时候创建动态代理的呢?

通常是在创建bean初始化之后创建动态代理. 如果有循环依赖,会在实例化之后创建动态代理,再来感受一下创建bean过程中的 *** 作.

 

下面我们来看正常的流程,在初始化之后创建AOP动态代理 .

在创建bean的过程中,一共有三步,来看看AbstractautowireCpablebeanfactory.doCreateBean()

protected Object doCreateBean(final String beanname,final RootBeanDeFinition mbd,final @Nullable Object[] args)            throws BeanCreationException {         Instantiate the bean.        BeanWrapper instanceWrapper = ;         (mbd.isSingleton()) {            instanceWrapper = .factorybeanInstanceCache.remove(beanname);        }        if (instanceWrapper == 第一步: 实例化            instanceWrapper = createBeanInstance(beanname,mbd,args);        }         这里使用了装饰器的设计模式        final Object bean = instanceWrapper.getWrappedInstance();        Class<?> beanType = instanceWrapper.getWrappedClass();        ......        try 第二步:填充属性,给属性赋值(调用set方法)  这里也是调用的后置处理器            populateBean(beanname,instanceWrapper);             第三步: 初始化.            exposedobject = initializeBean(beanname,exposedobject,mbd);        }        ......    }

 

在第三步初始化的时候,要处理很多bean的后置处理器. 

 Object applyBeanPostProcessorsAfterInitialization(Object existingBean,String beanname)            throws BeansException {        Object result = existingBean;        for (BeanPostProcessor processor : getBeanPostProcessors()) {            Object current = processor.postProcessAfterInitialization(result,beanname);            if (current == ) {                 result;            }            result = current;        }         result;    } 

 

postProcessAfterInitialization(result,beanname);就是处理初始化之后的后置处理器,下面就从这个方法作为入口分析. 

AnnotationAwareAspectJAutoproxyCreator也实现了postProcessAfterInitialization(result,beanname);接口

 Object  postProcessAfterInitialization(@Nullable Object bean,1)">*         * 每一个bean在解析的时候都会解析一遍切面.         * 为什么每次都要解析一遍呢? 因为还有另外一种方式-实现Advisor接口的方式实现AOP,在加载过程中,可能随时有新的bean被解析出来. 所以,需要每次都重新解析一遍,.         * 我们在第一次解析的Advisor都已经放入到缓存,在这里会先从缓存中取,也就是已经解析过的不会重复解析. 也就是不 消耗性能         if (bean !=  获取缓存key            Object cacheKey = getCacheKey(bean.getClass(),beanname);            *             * 因为有可能在循环依赖处理的时候已经创建国一遍,如果是那么现在就不再创建了,并且删除             * 在这里,我们要处理的是普通类的动态代理,所以,需要将循环以来创建的动态代理删掉             */            this.earlyProxyReferences.remove(cacheKey) != bean) {                 该方法将返回动态代理的实例                return wrAPIfNecessary(bean,cacheKey);            }        }         bean;    }

 

这里需要强调的一点是,每一个bean在解析的时候都会解析一遍切面.为什么每次都要解析一遍呢?因为创建切面有两种方式,一种是实现Advisor接口,另一种是注解的方式. 实现Advisor接口的方式, 在加载过程中, 可能随时有新的bean被解析出来. 所以, 需要每次都重新解析一遍.我们在第一次解析的Advisor都已经放入到缓存, 在这里会先从缓存中取, 也就是已经解析过的不会重复解析. 也就是不 消耗性能

 

接下来处理的流程如下:

 

这里,第三步:删除循环依赖创建的动态代理对象,为什么要这样处理呢?

因为有可能在循环依赖处理的时候已经创建了动态代理bean, 如果是,那么现在就不再创建了,并且将其删除. 在这里, 我们要处理的是普通类的动态代理, 所以, 需要将循环依赖创建的动态代理删掉 注: earlyProxyReferences对象使用来存储循环依赖过程中创建的动态代理bean. 如果循环依赖创建了这个代理bean,那么直接返回,如果没有创建过,我们再创建. 下面来看看是如何创建的?
 Object wrAPIfNecessary(Object bean,String beanname,Object cacheKey) {         已经被处理过(解析切面的时候,targetSourcedBeans用来存储自己实现创建动态代理的逻辑)        if (StringUtils.hasLength(beanname) &&  bean;        }         判断bean是否是需要增强的bean        *         * 哪些类是不需要增强的呢?         * 在解析切面的时候,基础类和应该跳过的类是不需要增强的.         if (Boolean.FALSE.equals(this.advisedBeans.(cacheKey))) {             判断是否是基础类,或者是否是需要跳过的类        if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(),beanname)) {             将其标记为不需要增强的类             bean;        }         匹配Advisor. 根据类匹配advisors,至少匹配上一个,才创建动态代理,否则不创建动态代理        Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(),null);         匹配了至少一个advisor,创建动态代理        if (specificInterceptors != DO_NOT_PROXY) {             createProxy(                    bean.getClass(),new SingletonTargetSource(bean));             bean;    }

 

来看看创建流程

 

 首先判断是否是需要跳过的类. 哪些类是需要跳过的类呢?

第一类:基础类. Advice,pointcut,Advisor,AopInfrastructureBean. 

第二类: 原始的接口类,以.ORIGINAL开头的类

 

 接下来, 匹配Advisor. 

protected List<Advisor> findEligibleAdvisors(Class<?> 第一步: 拿到已经解析出来的advisors(这次是从缓存中获取)        List<Advisor> candIDateAdvisors = findCandIDateAdvisors();         第二步:循环判断advisor能否作用于当前bean(原理: 切点是否命中bean)        List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candIDateAdvisors,beanClass,beanname);        第三步: 对匹配bean的advisor进行增强        extendAdvisors(eligibleAdvisors);         第四步: 对匹配bean的advisor进行排序        eligibleAdvisors.isEmpty()) {            eligibleAdvisors = sortAdvisors(eligibleAdvisors);        }         返回匹配到的advisors         eligibleAdvisors;    } 

 

这里经过了四步,具体详见上述代码及注释. 

第一步: 从缓存中拿到已经解析出来的advisors第二步:循环判断advisor能否作用于当前bean第三步: 对匹配bean的advisor进行增强第四步: 对匹配bean的advisor进行排序

 

 这里面的第一步: 从缓存中取出了已经解析出来的advisors集合. 解析方式是从缓存中取出已经解析的advisors

 接下来,循环遍历获得到的advisors,得到每一个advisor. 判断advisor是否是目标bean需要增强的通知.

 

 这里在筛选的时候,根据切点表达式进行了两次筛选. 第一次粗筛,第二次是精筛. 整个目标类,只要有一个类命中切点表达式,那么这个类就是需要被创建动态代理的类,返回true.

接下来就是要创建动态代理了. 然后,返回创建的动态代理对象.

下面来看看是如何创建动态代理的.

  

创建动态代理对象有两种方式: 一种是jdk代理,一种是cglib代理. 

无论是使用xml配置的方式,还是使用注解的方式,都有一个参数proxy-target-class,如果将这个参数设置为true,表示强制使用cglib代理. 如下所示设置:

使用注解的方式@EnableAspectJAutoproxy(proxyTargetClass=true)使用xml配置的方式<aop: sapectj-autoproxy proxy-target-></aop:>

所以在创建动态代理之前,先解析注解或者配置,看是否配置了proxy-target-class参数. 如果配置了这个参数,且其值为true,那么就创建一个cglib代理对象. 否则创建一个JDK代理对象.通常,我们使用的更多的是spring自己定义的JDK代理对象. 通过Proxy.newProxyInstance(classLoader,proxIEdInterfaces,this);创建动态代理


在JDKDynamicAopProxy代理类中有一个invoke()方法. 这个invoke方法,就是执行代理对象的方法时调用的方法.

 该方法是通过反射的方法执行目标类中定义的方法的. 

public Object invoke(Object proxy,Method method,Object[] args) throws Throwable { }
 3. 调用动态代理.

调用这里有一个非常经典的调用逻辑--调用链.

 

 如上图,调用链的逻辑是,调用动态代理方法,比如说div(arg1,arg2),然后执行调用链中第一个通知advisor1,然后第一个通知调用第二个通知,在执行第二个,以此类推,当所有的通知执行完,调用目标方法div(arg1,然后返回执行结果. 我们来看看代码的逻辑实现.

如下代码是调用动态代理的代码入口:

 

public class LxlMainClass {  public static voID main(String[] args) {    AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(MainConfig.class);    Calculate calculate = (Calculate) ctx.getBean("lxlCalculate");    /**     * 上面的calculate,就是返回的动态代理的类     * 当调用下面的div方法时,实际上调用的是JdkDynamicAopProxy.invoke(...)方法     */    calculate.div(2,4);    ProgramCalculate programCalculate = (ProgramCalculate) ctx.getBean("lxlCalculate");    String s = programCalculate.toBinary(5);    System.out.println(s);  }}

我们在main方法中,获取的Calculate对象,其实是动态代理生成的对象. 当调用calculate.div(2,4)方法时,其实调用的是动态代理的invoke()方法.

 Object invoke(Object proxy,Object[] args) throws Throwable {        Object oldProxy =  设置代理上下文        boolean setProxyContext = ;         目标源: 也就是目标代理的目标类        TargetSource targetSource = .advised.targetSource;        Object target =  {            this.equals@R_404_5552@d && AopUtils.isEqualsMethod(method)) {                 The target does not implement the equals(Object) method itself.                return equals(args[]);            }            else this.hashCode@R_404_5552@d && AopUtils.isHashCodeMethod(method)) {                 The target does not implement the hashCode() method itself.                 hashCode();            }            if (method.getDeclaringClass() == DecoratingProxy. There is only getDecoratedClass() declared -> dispatch to proxy config.                return AopProxyUtils.ultimateTargetClass(.advised);            }             如果方法所在类是一个接口 && 是可分配为Advised类型的方法            this.advised.opaque && method.getDeclaringClass().isInterface() &&                    method.getDeclaringClass().isAssignableFrom(Advised.)) {                 Service invocations on ProxyConfig with the proxy config...                return AopUtils.invokeJoinpointUsingReflection(.advised,method,args);            }            Object retVal;            .advised.exposeProxy) {                 把代理对象暴露在线程变量中.                oldProxy = AopContext.setCurrentProxy(proxy);                 设置代理的上下文为true                setProxyContext = ;            }             Get as late as possible to minimize the time we "own" the target,1)"> in case it comes from a pool.             获取目标对象            target = targetSource.getTarget();            Class<?> targetClass = (target != null ? target.getClass() : );             把aop的advisor全部转化为拦截器,通过责任链模式依次调用            *             * 将advisor对象转换为interceptor对象.             *             * 问题: 为什么要将advisor都转化为interceptor拦截器呢?             * 主要还是因为要进行责任链调用. 之前说过,要想进行责任链调用,他们要有一个共同的方法.             * 转化为interceptor以后,这里共同的方法就是invoke().             * beforeAdivsor,afteradvisor,returningAdvisor,throwingAdvisor. 这几种类型. 只有returningAdvisor和throwingAdvisor会转化为Interceptor.             * 因为beforeAdvisor和adgerAdvisor本身就实现了interceptor接口             */            List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method,targetClass);             拦截器链为空             (chain.isEmpty()) {                 通过反射直接调用执行目标方法                Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method,args);                retVal = AopUtils.invokeJoinpointUsingReflection(target,argsToUse);            }             创建一个 method invocation 拦截器                MethodInvocation invocation =                         ReflectiveMethodInvocation(proxy,target,args,targetClass,chain);                 Proceed to the joinpoint through the interceptor chain.                // 通过拦截器链调用连接点                retVal = invocation.proceed();            }             Massage return value if necessary.            Class<?> returnType = method.getReturnType();            if (retVal != null && retVal == target &&                    returnType != Object.class && returnType.isinstance(proxy) &&                    !RawTargetAccess..isAssignableFrom(method.getDeclaringClass())) {                 Special case: it returned "this" and the return type of the method                 is type-compatible. Note that we can't help if the target sets                 a reference to itself in another returned object.                retVal = proxy;            }            if (retVal == null && returnType != VoID.TYPE && returnType.isPrimitive()) {                 AopInvocationException(                        Null return value from advice does not match primitive return type for:  method);            }             retVal;        }        finallyif (target != null && !targetSource.isstatic()) {                 Must have come from TargetSource.                targetSource.releaseTarget(target);            }             (setProxyContext) {                 Restore old proxy.                AopContext.setCurrentProxy(oldProxy);            }        }    }

 

 这里有两步很重要:

第一步: 将匹配的advisor转换为Interceptor

第二步: 调用责任链,执行各类通知

 

 

 

先看第一步: 将匹配的advisor对象转换为interceptor拦截器对象. 为什么要将advisor转换为interceptor拦截器呢?

因为要进行责任链调用. 前面说过,他们要有一个共同的方法. 转化为interceptor以后,共同的方法就是invoke().

public List<Object> getInterceptorsAndDynamicInterceptionAdvice(            Advised config,@Nullable Class<?> targetClass) {         This is somewhat tricky... We have to process introductions first,1)"> but we need to preserve order in the ultimate List.        AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();         获取到匹配当前方法的所有advisor        Advisor[] advisors = config.getAdvisors();        List<Object> interceptorList = (advisors.length);        Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());        Boolean hasIntroductions =  (Advisor advisor : advisors) {            *             * 如果advisor是pointcutAdvisor类型             */             (advisor instanceof pointcutAdvisor) {                 Add it conditionally.                pointcutAdvisor pointcutAdvisor = (pointcutAdvisor) advisor;                 注解配置信息是一个前置过滤器 或者 目标类匹配advisor的切点表达式                if (config.isPreFiltered() || pointcutAdvisor.getpointcut().getClassFilter().matches(actualClass)) {                    MethodMatcher mm = pointcutAdvisor.getpointcut().getmethodMatcher();                    boolean match;                     (mm instanceof IntroductionAwareMethodMatcher) {                        if (hasIntroductions == ) {                            hasIntroductions = hasMatchingIntroductions(advisors,actualClass);                        }                        match = ((IntroductionAwareMethodMatcher) mm).matches(method,actualClass,hasIntroductions);                    }                     {                        match = mm.matches(method,actualClass);                    }                     (match) {                         将advice转换为MethodInterceptor拦截器,                        MethodInterceptor[] interceptors = registry.getInterceptors(advisor);                         (mm.isRuntime()) {                             Creating a new object instance in the getInterceptors() method                             isn't a problem as we normally cache created chains.                             (MethodInterceptor interceptor : interceptors) {                                 将MethodInterceptor拦截器和MethodMatcher组装为一个新的对象                                interceptorList.add( InterceptorAndDynamicmethodMatcher(interceptor,mm));                            }                        }                         {                            // 将拦截器直接放到interceptorList中                            interceptorList.addAll(Arrays.asList(interceptors));                        }                    }                }            }            if (advisor instanceof IntroductionAdvisor) {  如果advisor是IntroductionAdvisor类型                IntroductionAdvisor ia = (IntroductionAdvisor) advisor;                 ia.getClassFilter().matches(actualClass)) {                    Interceptor[] interceptors = registry.getInterceptors(advisor);                    interceptorList.addAll(Arrays.asList(interceptors));                }            }            else {  其他类型的advisor                Interceptor[] interceptors = registry.getInterceptors(advisor);                interceptorList.addAll(Arrays.asList(interceptors));            }        }         interceptorList;    }

 

这里最重要的方法就是registry.getInterceptors(advisor),在getInterceptors(advisor)里面循环遍历了advisors,然后将每一个advisor转换为Interceptor, 这是将advisor转换为interceptor的具体实现. 

我们来看看源码和逻辑

 MethodInterceptor[] getInterceptors(Advisor advisor) throws UnkNownAdviceTypeException {        List<MethodInterceptor> interceptors = new ArrayList<>(3);        Advice advice = advisor.getAdvice();         (advice instanceof MethodInterceptor) {             如果advice已经实现了MethodInterceptor接口,那么直接将其添加到interceptors集合中            interceptors.add((MethodInterceptor) advice);        }        for (AdvisorAdapter adapter : .adapters) {             判断是否是指定类型的advice             (adapter.supportsAdvice(advice)) {                 如果是就将其转换为对应类型的Interceptor                interceptors.add(adapter.getInterceptor(advisor));            }        }         (interceptors.isEmpty()) {             UnkNownAdviceTypeException(advisor.getAdvice());        }        return interceptors.toArray(new MethodInterceptor[]);    }

 

adapter.supportsAdvice(advice)判断advice是否是指定类型的adapter. adapter有如下几种

MethodBeforeAdviceAdapter : 前置通知adapterAfterReturningAdviceAdapter:后置|放回通知adapterSimpleBeforeAdviceAdapter: simpler前置通知adapterThrowsAdviceAdapter:异常通知adapter

这里采用的是适配器模式,通过适配器来匹配各种不同类型的通知. 然后再调用adapter.getInterceptor(advisor)将advisor构建成Interceptor.

通常有beforeAdivsor,throwingAdvisor几种类型的通知. 只有returningAdvisor和throwingAdvisor会转化为Interceptor.
因为beforeAdvisor和afteradvisor本身就实现了interceptor接口.

将所有的advisor转换成Interceptor以后放入到interceptors集合中返回.

 

接下来执行责任链调用.责任链调用的思想主要有两个

1. 递归调用

2. 所有的advisor最终都让其实现interceptor,并重写invoke()方法.

来看一下源码

 Object proceed() throws Throwable {         We start with an index of -1 and increment early.         如果是最后一个拦截器,则直接执行. invokeJoinpoint()方法        this.currentInterceptorIndex == this.interceptorsAndDynamicmethodMatchers.size() -  invokeJoinpoint();        }         取出interceptorsAndDynamicmethodMatchers对象        Object interceptorOrInterceptionAdvice =                this.interceptorsAndDynamicmethodMatchers.get(++.currentInterceptorIndex);         如果是InterceptorAndDynamicmethodMatcher类型         (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicmethodMatcher) {             Evaluate dynamic method matcher here: static part will already have             been evaluated and found to match.            InterceptorAndDynamicmethodMatcher dm =                    (InterceptorAndDynamicmethodMatcher) interceptorOrInterceptionAdvice;            Class<?> targetClass = (this.targetClass != null ? this.targetClass : .method.getDeclaringClass());             调用methodMather的matchs()方法            if (dm.methodMatcher.matches(this.method,1)">.arguments)) {                 匹配成功,则调用拦截器的invoke()方法                return dm.interceptor.invoke();            }             Dynamic matching Failed.                 Skip this interceptor and invoke the next in the chain.                 动态匹配失败,跳过此拦截器,调用拦截器链中的下一个拦截器                 proceed();            }        }         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();        }    }

 

在这里interceptorsAndDynamicmethodMatchers存放的就是所有匹配到的advisor. 按照顺序,取出advisor. 然后将其转换为MethodInterceptor以后,调用他的invoke(this)方法,同时将传递当前对象,在invoke(this)中在此调用proceed()方法. 循环调用. 从interceptorsAndDynamicmethodMatchers取advisor,直到取出最后一个advisor. 再次调用proceed()则指定调用目标方法.

interceptorsAndDynamicmethodMatchers里面一共有6个advisor

具体调用如下图:

 以上就是调用aop的整个过程. 内容还是很多的,需要时间消化.

总结

以上是内存溢出为你收集整理的5.2 spring5源码--spring AOP源码分析三---切面源码分析全部内容,希望文章能够帮你解决5.2 spring5源码--spring AOP源码分析三---切面源码分析所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/1215401.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-05
下一篇 2022-06-05

发表评论

登录后才能评论

评论列表(0条)

保存