• Spring-AOP源码分析随手记(一)


    1.@EnableAspectJAutoProxy(proxyTargetClass = true)

    就是弄了个"org.springframework.aop.config.internalAutoProxyCreator"::AnnotationAwareAspectJAutoProxyCreator.class的Bean到容器中

    2.分析AnnotationAwareAspectJAutoProxyCreator.class类结构

    得出了哪些是重要的几个。

    3.查看AnnotationAwareAspectJAutoProxyCreator源码

    =》查看父类AbstractAutoProxyCreator,有setBeanFactory等等各种继承来的方法

    4.又是一顿整理得出了一个图(???)如下

    pic1->AOP功能代码分析图

    image

    5.分析AbstractAutoProxyCreator。

    setBeanFactory有个O标志被重写了,打开,有个initBeanFactory方法,打开,创建了个advisorRetrievalHelper切面工具,又是O重写 创建了aspectJAdvisorsBuilder

    6.pic1图里明显看出有两个关键性方法:

    postProcessBeforeInstantiation和postProcessAfterInitialization

    显然是前后处理逻辑了。肯定先看前逻辑postProcessBeforeInstantiation啊

    7.postProcessBeforeInstantiation

    断点走起,居然是从这里进去的

    image

    image

    所以这个之前分析IOC的createBean里的resolveBeforeInstantiation是AOP实现的关键。

    8.分析postProcessBeforeInstantiation细节

    8.1 isInfrastructureClass判断是否基础Bean

    就是那种AOP本身的比如Advice、Pointcut、AopInfrastructureBean等,基础的这种直接返回不需要代理

    8.2 shouldSkip是否要跳过(包含找出切面)

    8.2.1找出增强器(那种切面里的@After、@Before的方法)

    跟随断点跳跃到之前setBeanFactory创建的advisorRetrievalHelper里去了帮忙实现的找增强器

    实际上这里面又分两部分了,一个是找事务的(findCandidateAdvisors)(本次断点容器和缓存中都就没用了直接返回空,不是事务,具体可以看aop源码instan...图)

    另一部分是this.aspectJAdvisorsBuilder.buildAspectJAdvisors()

    image

    跳进去看了下,它把所有的beanname拿出来找,去找切面类 找到了我写的MyLogAspect

    (打了切面切面注解)

    然后找到了切面类,调用相关封装的getAdvisors方法去拿增强器了。

    其实就是获取切面类的所有方法(getAdvisorMethods)把每个包含增强那些注解的方法包装成Advice 放进缓存。

    protected static AspectJAnnotation<?> findAspectJAnnotationOnMethod(Method method) {
       for (Class<?> clazz : ASPECTJ_ANNOTATION_CLASSES) {
          AspectJAnnotation<?> foundAnnotation = findAnnotation(method, (Class<Annotation>) clazz);
          if (foundAnnotation != null) {
             return foundAnnotation;
          }
       }
       return null;
    }
    

    private static final Class<?>[] ASPECTJ_ANNOTATION_CLASSES = new Class<?>[] {
          Pointcut.class, Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class};
    

    然后

    switch (aspectJAnnotation.getAnnotationType()) {
       case AtPointcut:
          if (logger.isDebugEnabled()) {
             logger.debug("Processing pointcut '" + candidateAdviceMethod.getName() + "'");
          }
          return null;
       case AtAround:
          springAdvice = new AspectJAroundAdvice(
                candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
          break;
       case AtBefore:
          springAdvice = new AspectJMethodBeforeAdvice(
                candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
          break;
       case AtAfter:
          springAdvice = new AspectJAfterAdvice(
                candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
          break;
       case AtAfterReturning:
          springAdvice = new AspectJAfterReturningAdvice(
                candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
          AfterReturning afterReturningAnnotation = (AfterReturning) aspectJAnnotation.getAnnotation();
          if (StringUtils.hasText(afterReturningAnnotation.returning())) {
             springAdvice.setReturningName(afterReturningAnnotation.returning());
          }
          break;
       case AtAfterThrowing:
          springAdvice = new AspectJAfterThrowingAdvice(
                candidateAdviceMethod, expressionPointcut, aspectInstanceFactory);
          AfterThrowing afterThrowingAnnotation = (AfterThrowing) aspectJAnnotation.getAnnotation();
          if (StringUtils.hasText(afterThrowingAnnotation.throwing())) {
             springAdvice.setThrowingName(afterThrowingAnnotation.throwing());
          }
          break;
       default:
          throw new UnsupportedOperationException(
                "Unsupported advice type on method: " + candidateAdviceMethod);
    }
    

    switch判断注解类型 创建不同类型Advice 放进缓存

    最终由this.aspectJAdvisorsBuilder.buildAspectJAdvisors()找到了我写的所有切面的增强方法

    最终把整个切面类放到了advisorsCache的ConcurrentHashMap,以切面类的beanname作为key,增强器方法advice集合作为value

    9.postProcessAfterInitialization

    条件断点,当beanname = "calculate"时停住。找出增强器后,看看后续aop是怎么和目标类结合的。

    10.postProcessAfterInitialization细节

    断点已达。老办法,看看是从哪调来的:

    image

    image

    原来是这里,ioc创建完对象并给属性赋完值之后。

    回到postProcessAfterInitialization本身,就调了个wrapIfNecessary。逻辑都在里面了

    10.1 找对应的增强器

    打开断点继续,先主要是个getAdvicesAndAdvisorsForBean然后调findEligibleAdvisors然后就是以前跑过的找事务略。然后主要是findAdvisorsThatCanApply(名字也看得出,它能用的 这个bean对应的切面),进去又是个canApply(candidate, clazz, hasIntroductions),这就是具体判断了:

    image

    image

    获取所有方法,用匹配器match去匹配是否匹配上了

    循环记下,全部找出来,找增强器就结束了!

    10.2 织入生成代理对象

    回到wrapIfNecessary开始创建代理对象了:

    image

    image

    这里面框起来是涉及注解配置的,对应你配置的:

    @EnableAspectJAutoProxy(exposeProxy = true)

    @EnableAspectJAutoProxy(proxyTargetClass = true)

    如果这两个设置了的话,就会处理实现。

    第二个是启动优先cglib,第一个是把代理对象创建好之后暴露出去,这样就能让原本this.dadd去调用方法本来不能增强的情况 可以用

    ((Calculate) AopContext.currentProxy()).add(numA,numB);也触发增强效果

    后面的话就是创建个代理工厂ProxyFactory,把增强器设置进去,最后调用getProxy

    一路跳转:

    image

    这就是最后网上背背背的东西了。在没有接口和没打优先cglib的话用jdk创建否则cglib创建。

    问题:

    1.怎么得出来继承结构哪些是重要的、哪些是不需要看不重要的

    2.怎么整理出来的?

  • 相关阅读:
    [ SSH框架 ] Hibernate框架学习之三
    [ Java学习基础 ] Java的对象容器 -- 集合
    [ Java学习基础 ] Java异常处理
    [ SSH框架 ] Hibernate框架学习之二
    [ Java学习基础 ] Java的抽象类与接口
    [ SSH框架 ] Hibernate框架学习之一
    [ Java学习基础 ] Java的继承与多态
    07 saltstack生产实例-mysql主从
    02 Vue介绍与安装,指令系统 v-*、音乐播放器
    01- ES6、jquery源码、node、webpack
  • 原文地址:https://www.cnblogs.com/chz-blogs/p/12005744.html
Copyright © 2020-2023  润新知