美文网首页
【Spring源码】20.AOP之切面的收集

【Spring源码】20.AOP之切面的收集

作者: 天还下着毛毛雨 | 来源:发表于2023-02-08 21:03 被阅读0次
    image

    1. 前言

    我们知道aop实现的原理肯定是基于jdk动态代理和cglib代理,经过生成代理对象,对命中切面的方法进行增强。并将代理对象存放到ioc容器中,在其他对象需要的时候注入进去, 那么肯定 需要通过解析类 去解析 并收集 Advisor对象集合 : 需要增强的目标PointCut 以及 具体增强的逻辑Advice。 如果这个类是可以找到增强对象的,那么就应该生成代理。

    2. 问题

    2.1 生成的代理对象需要什么?

    首先 需要进行 切面的收集和匹配

    然后 把匹配到的切面 放入 生成的代理对象里,以便后续调用代理方法 来 决定调用哪个切面 来增强。

    我们来看下wrapIfNecessary方法里是如何 进行切面的收集和匹配的。

    image

    3. Advisor增强对象的收集和匹配

    3.1 Advisor增强对象的收集

    该方法会先收集适合所有的Advisor增强对象,并过滤出匹配当前bean的Advisor对象

    image

    getAdvicesAndAdvisorsForBean

    image

    收集及匹配全在这

    image

    先看收集所有的切面findCandidateAdvisors()

    这个方法是被他的子类重写并调用的,看子类AnnotationAwareAspectJAutoProxyCreator的该方法

    image image

    spring自带的advisors可以不看,我们直接看我们自己写的@Aspect类

    image

    这里有两个缓存

    image

    buildAspectJAdvisors方法里会先判断缓存

    image

    第一次没有,肯定先解析再获取,我们看解析的逻辑

    可以看到会遍历spring容器里的每一个beanName,然后根据beanName获取class,如果类上有Aspect注解,说明是需要解析的

    将 beanFactory, beanName 封装成一个获取Advisor的工厂,然后调用 this.advisorFactory.getAdvisors(factory) 去获取advisors集合

    image

    3.1.1. 获取没有 @PointCut注解的方法集合

    取出从获取advisors工厂里取出beanClass, 去遍历所有没有@PointCut注解的方法,包含什么注解也没有的方法

    image

    具体怎么获取,也很简单,遍历每一个方法,如果没有@Pointcut 注解就可以

    image

    3.1.2. 对要解析的方法集合排序

    随后会对 没有@PointCut注解的方法集合进行排序, 按照这个顺序排序 : Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class

    image

    METHOD_COMPARATOR 比较器 :

    image

    3.1.3. 遍历没有@PointCut注解的方法的集合,开始创建Advisor对象

    这里就开始要根据方法上面 aop相关的注解 来常见Advisor对象。

    首先需要明确一点,Advisor定义的 是 增强的目标 与 增强的逻辑,

    1. 增强的目标 则是Pointcut对象定义的
    2. 增强的逻辑 则是Advice对象定义的

    所以,Advisor 必须要包含Pointcut对象和 Advice对象。

    image

    3.1.3.1. Pointcut接口介绍

    基于表达式的PointCut实现类是 AspectJExpressionPointcut类,它除了多持有一个表达式外,还会实现的 Pointcut接口。

     public interface Pointcut {
    
       ClassFilter getClassFilter();
    
       MethodMatcher getMethodMatcher();
    
       Pointcut TRUE = TruePointcut.INSTANCE;
    }
    

    需要重写getClassFilter()来提供ClassFilter, ClassFilter是一个接口,重写matches方法,来定义是否与类匹配

    @FunctionalInterface
    public interface ClassFilter {
            // 定义是否与类匹配
       boolean matches(Class<?> clazz);
    
       ClassFilter TRUE = TrueClassFilter.INSTANCE;
    }
    

    重写 getMethodMatcher()方法 来提供MethodMatcher 对象, MethodMatcher也是一个接口

    public interface MethodMatcher {
      // 定义是否与类匹配
       boolean matches(Method method, Class<?> targetClass);
    
       boolean isRuntime();
         // 定义是否与方法匹配
       boolean matches(Method method, Class<?> targetClass, Object... args);
    
       MethodMatcher TRUE = TrueMethodMatcher.INSTANCE;
    }
    

    这里AspectJExpressionPointcut类,自己实现了ClassFilter接口,和IntroductionAwareMethodMatcher接口,可以看到实现至Pointcut接口接口的两个方法 返回的都是自身。

    image 重写自ClassFilter接口,和IntroductionAwareMethodMatcher接口 对应的matches方法。 image

    这里先这样,后面匹配的时候 再看这两个方法里具体的匹配逻辑。

    3.1.3.2. PointCut对象的创建

    进入 getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
    int declarationOrderInAspect, String aspectName) 方法

    image

    进入 getPointcut方法,这里先获取Pointcut.class, Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class 这几个注解,匹配到就返回

    不可能获取到@Pointcut注解
    其实这里是不可能获取到 @Pointcut ,因为前面 遍历的整个方法的集合 就已经是排除掉了 @Pointcut注解的方法
    
    获取需要遍历的整个方法集合代码                 ![image](https://img.haomeiwen.com/i23353704/e4ef94bec8d68a4a.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
    

    getPointcut方法

    注解获取到Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class注解里的其中任意一个,获取注解里的pointcutExpression属性,以及目标类的class对象,设置到创建的AspectJExpressionPointcut对象里,并返回

    image

    到这里pointCut对象已经创建完成,其实并不会去 扫描有@PointCut注解的方法,只是通过Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class里的pointcut属性,去指向@PointCut注解的方法,到时候可以 根据这个 去找 @PointCut注解的方法,再去找@PointCut里面具体配置的表达式,明确切点。

    3.1.3.3. Advice对象的创建

    代码回到入 getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
    int declarationOrderInAspect, String aspectName) 方法。

    会new出InstantiationModelAwarePointcutAdvisorImpl对象, 传入AspectJExpressionPointcut对象到构造方法里

    image

    InstantiationModelAwarePointcutAdvisorImpl构造方法

    会先存PointCut对象以及原生Method对象,再在instantiateAdvice方法里创建Advice对象

    image

    instantiateAdvice方法里创建Advice对象

    image

    首先从原生method方法,取出 Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class 这五个注解中的一个(一个方法只能取到其中一个注解,一般只会配一个)

    image

    再判断注解,根据注解的不同,创建的Advice对象也不同

    image

    可以看到注解与创建的AspectJAroundAdvice类有如下对应关系

    注解 Aavice实现类
    @Around AspectJAroundAdvice
    @Before AspectJMethodBeforeAdvice
    @After AspectJAfterAdvice
    @AfterReturning AspectJAfterReturningAdvice
    @AfterThrowing AspectJAfterThrowingAdvice
    MethodInterceptor接口

    其中AspectJAroundAdvice,AspectJMethodBeforeAdvice,AspectJAfterAdvice这三个类是实现MethodInterceptor接口的

    实现的invoke方法 持有 整个aop切面调用链上下文对象,以完成 切面调用链的回调,继续调用剩下的的 切面。

    @FunctionalInterface
    public interface MethodInterceptor extends Interceptor {
       Object invoke(MethodInvocation invocation) throws Throwable;
    }
    
    public class AspectJAfterAdvice extends AbstractAspectJAdvice
          implements MethodInterceptor, AfterAdvice, Serializable {
       @Override
       public Object invoke(MethodInvocation mi) throws Throwable {
          try {
             return mi.proceed();
          }
          finally {
             invokeAdviceMethod(getJoinPointMatch(), null, null);
          }
       }
    }
    public class AspectJMethodBeforeAdvice extends AbstractAspectJAdvice implements MethodBeforeAdvice, Serializable {
        public Object invoke(){
        // 继承的父类 AbstractAspectJAdvice的invoke
        }
        @Override
        public void before(Method method, Object[] args, @Nullable Object target) throws Throwable {
            invokeAdviceMethod(getJoinPointMatch(), null, null);
        }
    }
    
    public class AspectJAfterAdvice extends AbstractAspectJAdvice
            implements MethodInterceptor, AfterAdvice, Serializable {
        @Override
        public Object invoke(MethodInvocation mi) throws Throwable {
            try {
                return mi.proceed();
            }
            finally {
                invokeAdviceMethod(getJoinPointMatch(), null, null);
            }
        }
    }
    

    而AspectJAfterReturningAdvice,AspectJAfterThrowingAdvice这两个切面没有,到时候aop调用的时候,会对这两个切面类进行 MethodInterceptor类型适配,以保证 调用和调用链 传递逻辑的 统一。

    最终返回 各自的切面对象。

    image

    Advisor对象创建完成,存入缓存

    直到所有方法都扫描完成,对应的Advisor对象 也创建成功,都存入缓存: beanName -> 对应类解析出来的 advisors

    image

    至此, 当容器内所有的beanName都遍历完成,对应的class 通过解析、创建出来的Advisor对象全部 收集完毕。

    image

    相关文章

      网友评论

          本文标题:【Spring源码】20.AOP之切面的收集

          本文链接:https://www.haomeiwen.com/subject/hytckdtx.html