【Spring注解】AOP

AOP原理分析就是看给容器中注入了什么组件,这个组件什么时候工作,这个组件工作时候的功能

AOP的使用

详细的AOP功能

实现AOP的详细步骤

  1. 导入aop模块

            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-aspects</artifactId>
                <version>5.2.5.RELEASE</version>
            </dependency>
    
  2. 定义一个业务逻辑类(MathCalculator)
    在这里插入图片描述

  3. 定义一个日志切面类

  • 加@Aspect 注解 表明这是一个切面类
  • 在对应的方法上加对应的通知注解
    在这里插入图片描述
  1. 配置类
    • 将切面类和业务逻辑类加入到容器中
    • 开启基于注解的aop模式 @EnableAspectJAutoProxy
      5.

测试:
在这里插入图片描述
结果:
在这里插入图片描述

@EnableAspectJAutoProxy

@EnableAspectJAutoProxy注解利用AspectJAutoProxyRegistrar给容器中创建了AnnotationAwareAspectJAutoProxyCreator的beandefinition信息,IOC容器在注册后置处理器的时候就会根据这个beandefinition信息创建AnnotationAwareAspectJAutoProxyCreator的bean 实例

  1. @EnableAspectJAutoProxy
    EnableAspectJAutoProxy上导入了AspectJAutoProxyRegistrar
    在这里插入图片描述

AnnotationAwareAspectJAutoProxyCreator的定义信息beandefinition的注册

  1. AspectJAutoProxyRegistrar
    AspectJAutoProxyRegistrar实现了ImportBeanDefinitionRegistrar, 也就是自定义方式给容器中注册组件
    AspectJAutoProxyRegistrar 给容器中加入的是beanDefinition ,也就是告诉容器要创建的类型是AnnotationAwareAspectJAutoProxyCreator,名字是
    internalAutoProxyCreator

    在这里插入图片描述

    AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry); //通过这个方法注册的bean
    

    这个函数里具体注册bean的 是registerOrEscalateApcAsRequired方法

    在这里插入图片描述

     registry.registerBeanDefinition("org.springframework.aop.config.internalAutoProxyCreator", beanDefinition);
    

    通过上面这一句给容器中注入了AnnotationAwareAspectJAutoProxyCreator的定义信息beanDefinition

AnnotationAwareAspectJAutoProxyCreator 的注册

AnnotationAwareAspectJAutoProxyCreator是 注解模式的AspectJ切面自动代理创建器

父类

通过追溯AnnotationAwareAspectJAutoProxyCreator 的父类 我们可以看到
它其实 实现了两个接口

  • SmartInstantiationAwareBeanPostProcessor 后置处理器
  • BeanFactoryAware Aware接口的实现类

AnnotationAwareAspectJAutoProxyCreator
-> AspectJAwareAdvisorAutoProxyCreator
-> AbstractAdvisorAutoProxyCreator
->AbstractAutoProxyCreator
->ProxyProcessorSupport
实现SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware
在这里插入图片描述

其中SmartInstantiationAwareBeanPostProcessor的父类
SmartInstantiationAwareBeanPostProcessor
->InstantiationAwareBeanPostProcessor
->BeanPostProcessor

可以看到就是后置处理器

创建ioc容器

在这里插入图片描述
AnnotationConfigApplicationContext:
在这里插入图片描述
做了三步

  • 调用无参构造器
  • 注册配置类
  • 调用refresh() 刷新容器
    refresh() :
    中注册bean的后置处理器 用来拦截bean的创建
    在这里插入图片描述
registerBeanPostProcessors 注册BeanPostProcessor

registerBeanPostProcessors 方法:
在这里插入图片描述

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

    String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
    

    现在这些 BeanPostProcessor 都是BeanDefinetion 还没有创建对象在这里插入图片描述

  • 给容器中加入别的BeanPostProcessor

    	beanFactory.addBeanPostProcessor(new PostProcessorRegistrationDelegate.BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));
    
  • 将BeanPostProcessor分类 , 并注册

    • 实现了PriorityOrdered接口的 priorityOrderedPostProcessors[实现这个接口的有优先级排序]
      在这里插入图片描述

    • 实现了Ordered接口的orderedPostProcessors
      在这里插入图片描述

    • 没有实现Oredered接口的nonOrderedPostProcessors
      在这里插入图片描述

    • 是MergedBeanDefinitionPostProcessor的 internalPostProcessors
      这个internalPostProcessors 遍历前面的时候都往这里加,我还没搞懂为这个处理器是个什么东西在这里插入图片描述

      上面的顺序就是注册顺序,即优先注册实现了PriorityOrdered接口的 BeanPostProcessor,再给容器中注册实现了Ordered接口的BeanPostProcessor,再注册实现Oredered接口的,最后实现是MergedBeanDefinitionPostProcessor的

    上面这些注册调用的registerBeanPostProcessors如下:
    拿到所有的后置处理器,调用beanFactory.addBeanPostProcessor ,即把BeanPostProcessor注册到BeanFactory中
    在这里插入图片描述

  • 注册一个ApplicationListenerDetector

 beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));

ApplicationListenerDetector是在Bean创建完成后检查是不是ApplicationListener
在这里插入图片描述

创建BeanPostProcessor对象

注册BeanPostProcessor,实际上就是创建BeanPostProcessor对象,保存在容器中

从registerBeanPostProcessors方法中
会调用beanFactory.getBean 来获取对象(名字为internalAutoProxyCreator,类型为后置处理器),那我们第一次是没有这个对象的 ,所以就会创建一个对象

在这里插入图片描述

  • beanFactory.getBean()
    会调用doGetBean

        public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
           return this.doGetBean(name, requiredType, (Object[])null, false);
       }
    
  • doGetBean
    首先通过getSingleton 获取 这个单实例对象, 获取不到,就用 createBean() 创建bean
    在这里插入图片描述

    • getSingleton 先去获取bean
      首先通过getSingleton 用singletonFactory.getObject()获取bean

      singletonObject = singletonFactory.getObject();
      

      我们第一次访问 肯定是没有的, 所以肯定是要去创建
      在这里插入图片描述

    • createBean() 创建bean
      通过这一句调用

       return this.createBean(beanName, mbd, args);
      

      参数:
      在这里插入图片描述
      调用doCreateBean
      在这里插入图片描述

  • doCreateBean

    • 创建bean的实例
      在这里插入图片描述

    • 属性赋值

      this.populateBean(beanName, mbd, instanceWrapper);
      
    • 初始化bean initializeBean

      • invokeAwareMethods
        处理Aware接口的方法回调(利用这些Aware接口对应的方法进行处理)在这里插入图片描述

      • applyBeanPostProcessorsBeforeInitialization
        应用后置处理器的postProcessBeforeInitialization方法
        在这里插入图片描述

      • invokeInitMethods
        执行自定义的初始化方法

      • applyBeanPostProcessorsAfterInitialization
        执行后置处理器的postProcessAfterInitialization方法
        在这里插入图片描述

BeanFactoryAware

通过分析AnnotationAwareAspectJAutoProxyCreator的父类,我们知道它实现了 BeanFactoryAware,所以我们分析它作为Aware做了哪些工作

实现了BeanFactoryAware的setBeanFactory方法的父类

首先找到所有实现了BeanFactoryAware的setBeanFactory方法的父类:
AbstractAdvisorAutoProxyCreator
AbstractAutoProxyCreator

所以上面创建IOC容器走到了doCreateBean 创建AnnotationAwareAspectJAutoProxyCreator类型的名为internalAutoProxyCreator 的 bean 时
初始化initializeBean 中 先调用了invokeAwareMethods方法

invokeAwareMethods

由于 实现了BeanFactoryAware,所以这里时true 就去调用setBeanFactory方法
在这里插入图片描述

setBeanFactory

调用的AnnotationAwareAspectJAutoProxyCreator的父类AbstractAdvisorAutoProxyCreator的setBeanFactory方法

在这里插入图片描述

  • 父类的setBeanFactory方法
    AbstractAdvisorAutoProxyCreator的父类AbstractAutoProxyCreator也实现了BeanFactoryAware,所以会调用 AbstractAutoProxyCreator的setBeanFactory方法
  • AnnotationAwareAspectJAutoProxyCreator重写的initBeanFactory方法
    这个方法中调用了initBeanFactory方法,这个方法被AnnotationAwareAspectJAutoProxyCreator重写了,所以调用的是AnnotationAwareAspectJAutoProxyCreator重写的initBeanFactory方法
    在这里插入图片描述

AnnotationAwareAspectJAutoProxyCreator 作为后置处理器所做的工作

AnnotationAwareAspectJAutoProxyCreator 是一个后置处理器, 上面我们已经把它放在容器中了,之后任何组件在创建对象的时候 它就可以发挥作用,主要是两个作用:

  • 在bean创建前尝试返回对象
    通过AbstractAutoProxyCreator 实现的postProcessBeforeInstantiation 方法(这个方法是InstantiationAwareBeanPostProcessor )

    AnnotationAwareAspectJAutoProxyCreator 的父类AbstractAutoProxyCreator实现的是SmartInstantiationAwareBeanPostProcessor:

    public interface SmartInstantiationAwareBeanPostProcessor extends InstantiationAwareBeanPostProcessor {
    

    InstantiationAwareBeanPostProcessor 的方法是BeforeInstantiation
    在这里插入图片描述

  • 在创建对象后 , 通过postProcessAfterInitialization 对对象进行增强
    通过AbstractAutoProxyCreator 实现的postProcessAfterInitialization方法(这个方法是BeanPostProcessor )

    SmartInstantiationAwareBeanPostProcessor继承了BeanPostProcessor

    public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor
    

因为两种后置处理器类型不一样

  • BeanPostProcessor
    方法是BeforInitialization
    是在Bean对象创建完成初始化前后调用
  • InstantiationAwareBeanPostProcessor (继承了BeanPostProcessor)
    方法是BeforeInstantiation
    是在创建Bean实例之前尝试用后置处理器返回对象的

finishBeanFactoryInitialization

首先还是创建ioc容器, 在refresh() 方法中调的是finishBeanFactoryInitialization
在这里插入图片描述

finishBeanFactoryInitialization 方法是用来完成beanFactory初始化的,也就是来创建剩下的单实例bean.(因为之前已经创建了后置处理器之类的bean)

finishBeanFactoryInitialization 方法如下:
调用preInstantiateSingletons 创建剩余的单实例
在这里插入图片描述

  • preInstantiateSingletons
    获取容器中所有的bean 放到beanNames里
    在这里插入图片描述

然后遍历beanNames, 通过getBean(beanName)来获取对象
在这里插入图片描述
在这里插入图片描述

创建bean

  • getBean
    getBean会调用doGetBean
        public Object getBean(String name) throws BeansException {
            return this.doGetBean(name, (Class)null, (Object[])null, false);
        }
    
  • doGetBean
    • 先从缓存中获取当前bean
      在这里插入图片描述

    • 缓存中获取不到再创建
      在这里插入图片描述

  • createBean
    在这里插入图片描述
    我们创建calculator的时候,第一步即resolveBeforeInstantiation返回的是null,因此会执行doCreate 来创建对象
    • resolveBeforeInstantiation 解析BeforeInstantiation
      给后置处理器一个机会来返回代理对象,而不是target bean instance.也就是希望后置处理器能在此返回一个代理对象. 如果能返回代理对象就使用,如果不能就调用doCreateBean
      在这里插入图片描述

      applyBeanPostProcessorsBeforeInstantiation

      resolveBeforeInstantiation 中通过applyBeanPostProcessorsBeforeInstantiation方法尝试返回代理对象

      拿到所有的后置处理器,如果这个后置处理器是InstantiationAwareBeanPostProcessor,就调用postProcessBeforeInstantiation方法
      在这里插入图片描述

      postProcessBeforeInstantiation

      postProcessBeforeInstantiation 是用来对 那些循环依赖的对象 提前创建代理对象,所以这个方法里 主要是判断那些不需要生成代理对象的就直接返回,需要的才生成代理对象.
      在这里插入图片描述

      下面的是MathCalculator

      • 不需要生成代理对象的 直接返回null
        • 判断当前bean是否在advisedBeans中
          advisedBeans中保存了所有需要增强的bean,
        • 判断当前bean是否是基础类型isInfrastructureClass或切面
          在这里插入图片描述
          • 判断是否是基础类型 super.isInfrastructureClass(beanClass)
            基础类型也就是是否实现了Advice\ PointCut\Advisor\AopInfrastructureBean
            在这里插入图片描述
          • 判断是否是切面 this.aspectJAdvisorFactory.isAspect(beanClass)
            判断是不是标了@Aspect
            在这里插入图片描述
        • 判断是否需要跳过shouldSkip
          在这里插入图片描述
          增强器:
          就是切面里的通知方法标了@Befor @After @AfterReturning @AfterThrowing @Around注解的
          我们给MathCalculator增强的方法如下:
          在这里插入图片描述
          所以这里的candidateAdvisors有四个
          每个通知方法的类型是InstantiationModelAwarePointcutAdvisor
          在这里插入图片描述
          所以它判断每个通知方法是不是AspectJPointcutAdvisor类型的,我们这里的方法都是InstantiationModelAwarePointcutAdvisor类型的,所以都返回false
        • targetSource == null
          这种也是返回null
      • 需要生成代理对象的 返回proxy
        在这里插入图片描述MathCalculator 的postProcessBeforeInstantiation 完 返回null
    • doCreateBean

      由于上面的返回null,所以调用doCreateBean创建对象

      • 创建MathCalculator对象
        是跳到这里创建的MathCalculator的对象 在这里插入图片描述

      • 创建AOP代理
        在doCreateBean的initializeBean 中,会通过applyBeanPostProcessorsAfterInitialization 来找到所有后置处理器
        initializeBean 方法:
        在这里插入图片描述
        ,我们目前关注的是我们这个AnnotationAwareAspectJAutoProxyCreator 后置处理器,所以下面的postProcessAfterInitialization 也是AnnotationAwareAspectJAutoProxyCreator 实现的方法,所以applyBeanPostProcessorsAfterInitialization 目前停在的是这个在这里插入图片描述

postProcessAfterInitialization

下面具体看AnnotationAwareAspectJAutoProxyCreator 的postProcessAfterInitialization方法具体做了什么
在这里插入图片描述
postProcessAfterInitialization 主要调了wrapIfNecessary方法

wrapIfNecessary方法中:
在这里插入图片描述

最终wrapIfNecessary给容器中返回当前组件使用cglib增强了的代理对象
以后容器中获取到的就是这个组件的代理对象,执行目标方法的时候代理对象就会执行通知方法的流程

  • 判断是否在targetSourcedBeans

  • 判断是不是在advisedBeans

  • 判断是不是切面

  • getAdvicesAndAdvisorsForBean
    获取当前bean的可用的增强器(通知方法),用的是findEligibleAdvisors方法
    在这里插入图片描述

    • findEligibleAdvisors
      找当能在当前bean使用的增强器(也就是找哪些通知方法是需要切入当前bean方法的)
      在这里插入图片描述

      • findCandidateAdvisors() 找到所有的候选增强器
        在这里插入图片描述

      • findAdvisorsThatCanApply 找到当前bean能使用的增强器
        找哪些通知方法是要切入到当前bean方法的
        在这里插入图片描述

        • AopUtils.findAdvisorsThatCanApply
          遍历所有的Advisors, 看是IntroductionAdvisor 还是不是 IntroductionAdvisor在这里插入图片描述

        • canApply

          通过算切入点表达式看能不能匹配 在这里插入图片描述

      • 对增强器进行排序

  • advisedBeans.put 保存当前bean在advisedBeans
    存在advisedBeans 中表示这个bean已经被增强处理了

  • 创建代理对象
    如果我们的bean是需要增强的就会来到这一步,创建当前bean的代理对象
    主要用到的是createProxy方法
    在这里插入图片描述

    • 获取所有增强器,保存到proxyFactory中在这里插入代码片

          Advisor[] advisors = this.buildAdvisors(beanName, specificInterceptors);//获取所有增强器
          proxyFactory.addAdvisors(advisors); //保存到proxyFactory中
      
    • 用代理工厂proxyFactory 创建对象
      在这里插入图片描述
      在这里插入图片描述

      • getAopProxyFactory() 得到AOP代理的创建工厂
      • createAopProxy 创建AOP代理
        • 创建Jdk动态代理
          类是有实现接口的
        • 还是cglib动态代理
          没有实现接口在这里插入图片描述

目标方法的执行流程

首先来看一下 容器中保存的cglib增强后的代理对象mathCalculator 包含的内容:

  • 通知方法的信息
    在这里插入图片描述

  • 要切入的目标对象

在 mathCalculator.div(1,1)处打一个断点,看这个方法具体是怎么执行的
在这里插入图片描述
进入的是CglibAopProxy.intercept 方法:
在这里插入图片描述

  • 获取拦截器链
     //根据ProxyFactory对象获取将要执行的目标方法的拦截器链
     List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
    
    连接器链就是 每个advisor 包装成MethodInterceptor
    • 没有拦截器链 直接执行目标方法
    • 有拦截器链
      把需要执行的目标对象,目标方法,拦截器链等信息传入创建CglibMethodInvocation对象,并调用proceed方法
      retVal = (new CglibAopProxy.CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy)).proceed();
      

获取拦截器链

最后得到的拦截器链
在这里插入图片描述

根据ProxyFactory对象获取将要执行的目标方法的拦截器链,拦截器链中就是 每个通知方法包装成MethodInterceptor

List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

这一句会调 getInterceptorsAndDynamicInterceptionAdvice方法:
用advisor链的工厂获取
在这里插入图片描述
getInterceptorsAndDynamicInterceptionAdvice:
遍历所有的增强器,根据增强器是PointcutAdvisor IntroductionAdvisor 还是其它 ,将器转为对应的interceptors,放到interceptorList中

  • List interceptorList = new ArrayList(advisors.length);
    保存所有拦截器:一个默认的ExposeInvocationInterceptor和我们定义的4个增强器
    在这里插入图片描述

  • PointcutAdvisor
    在这里插入图片描述

  • IntroductionAdvisor
    在这里插入图片描述

  • 其它
    在这里插入图片描述

registry.getInterceptors:
将增强器转为MethodInterceptor
在这里插入图片描述

  • advisor是MethodInterceptor
    直接返回
  • advisor不是MethodInterceptor
    用对应的适配器 将其转成MethodInterceptor
    所有的适配器
    在这里插入图片描述

执行拦截器链

在这里插入图片描述

执行拦截器链 就是目标方法通知方法的执行过程
通过拦截器链的机制,保证通知方法和目标方法的执行顺序

 retVal = (new CglibAopProxy.CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy)).proceed();

是先创建CglibMethodInvocation对象,然后调用它的proceed()
proceed()的过程:
在这里插入图片描述

  • 判断当前索引和和拦截器-1大小是否相等
            if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
                return this.invokeJoinpoint(); //执行目标方法
    
    currentInterceptorIndex 默认是-1
    因此 如果没有拦截器,就会执行目标方法;或者到了最后一个拦截器 也会执行目标方法
  • 通过索引获取到拦截器,每一个拦截器执行自己的invoke方法
    自己的invoke方法又会调用CglibMethodInvocation的proceed方法,因为索引加1 了,也就是执行了下一个拦截器
    所以等下一个拦截器执行完成返回以后再来执行
    通过索引得到获取拦截器:
    Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
    
    • ExposeInvocationInterceptor
      索引是0获取到的拦截器是ExposeInvocationInterceptor,直接执行自己的invoke方法:
      其中,this就是之前创建的CglibMethodInvocation对象

      return ((MethodInterceptor)interceptorOrInterceptionAdvice).invoke(this);
      

      ExposeInvocationInterceptor的invoke()方法:
      就是把CglibMethodInvocation作为共享数据放进去,然后执行CglibMethodInvocation的proceed方法(相当于调用了下一个拦截器)在这里插入图片描述
      invocation:

      	private static fin al ThreadLocal<MethodInvocation> invocation;
      

      ThreadLocal就是同一条线程共享数据的, 共享的数据是MethodInvocation ,即CglibMethodInvocation对象

    • AspectJAfterThrowingAdviceInterceptor
      在这里插入图片描述

      上面的拦截器调用CglibMethodInvocation.proceed 由于索引加1 索引是1得到AspectJAfterThrowingAdvice,拦截器,AspectJAfterThrowingAdvice调用自己的invoke方法如下:

      • 调用下一个拦截器
        也是通过调用 CglibMethodInvocation的invoke 调用下一个拦截器
      • 如果有异常
        会通过try catch 捕获到异常,然后执行标了@AfterThrowing注解的方法
    • AfterRetruningAdviceInterceptor

      • 调用下一个拦截器
      • 执行自己的afterReturning方法有异常的话这一句就不会执行
        等到之前的都return了之后,就会执行标了@afterRetruning方法. 如果之前执行的有异常,那这一句就不会执行.
    • AspectJAfterAdviceInterceptor
      在这里插入图片描述

      • 调用下一个拦截器
        下一个拦截器是标了@Before的方法,调完这个会执行被增强的方法
      • 调用invokeAdviceMethod
        这里就是调用@After标的方法,这个是用finally包的,所以不管有无异常这一句都会执行
    • MethodBeforeAdviceInterceptor
      在这里插入图片描述

      • 先执行@Before方法
      • 再执行mi.proceed
        因为是最后一个拦截器了所以满足这个条件们就会调用被增强的方法
        if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
        return this.invokeJoinpoint();//调用被增强的方法
        

AOP原理总结

  1. @EnableAspectJAutoProxy 开启AOP功能
  2. @EnableAspectJAutoProxy会给容器中注册一个组件AnnotationAwareAspectJAutoProxyCreator
  3. AnnotationAwareAspectJAutoProxyCreator是一个后置处理器
  4. 容器创建流程:
    • refresh()的registerBeanPostProcessors() 是注册后置处理器的,这里会创建 AnnotationAwareAspectJAutoProxyCreator对象
    • refresh()的finishBeanFactoryInitialization() 会初始化剩下的单实例bean
      • 这里会创建业务逻辑组件和切面组件
      • AnnotationAwareAspectJAutoProxyCreator 就会拦截组件的创建过程
      • 组件创建完后, 初始化后还会判断组件是否需要增强
        需要增强,就会把切面的通知方法包装成增强器,然后给业务逻辑组件创建一个代理对象
  5. 执行目标方法
    也就是代理对象执行目标方法
    使用CglibAopProxy.intercept()进行拦截:
    * 得到目标方法的拦截器链(增强器包装成拦截器MethodInterceptor)
    * 利用拦截器的链式机制,依次进入每一个拦截器进行执行
    * 效果:
    正常执行:前置通知->目标方法->后置通知->返回通知
    正常执行:前置通知->目标方法->后置通知->异常通知
  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值