• AOP源码解析


    一、AOP整体流程介绍

      

      1、spring 实例化单例bean,第一次调用后置处理器,解析切面@Aspect ,解析切面中的 @Pointcut @befor @after等,生成advisors(说明 一个 @before + 切点 生成一个advisor)

        1.1  org.springframework.context.support.AbstractApplicationContext#refresh() 方法

        1.2 org.springframework.context.support.AbstractApplicationContext#finishBeanFactoryInitialization(beanFactory); // 实例化我们剩余的单实例bean.

        1.3 org.springframework.beans.factory.support.DefaultListableBeanFactory#preInstantiateSingletons 

        1.4 org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean 创建bean方法

        1.5 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean()真正创建bean的方法

          Object bean = resolveBeforeInstantiation(beanName, mbdToUse); 在此处调用 第一个后置处理器(InstantiationAwareBeanPostProcessor),解析切面,生成advisors ,进行缓存

        1.6 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsBeforeInstantiation 

          InstantiationAwareBeanPostProcessor 后置处理器实现了 BeanpostProcessor ,有2个接口

          方法1:postProcessBeforeInitialization   在bean初始化之前调用,用于解析切面,生成advisors

          方法2:postProcessAfterInitialization  bean初始化之后调用,用于 生成代理对象

        1.7 org.springframework.aop.aspectj.autoproxy.AspectJAwareAdvisorAutoProxyCreator#shouldSkip 

        1.8 org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator#findCandidateAdvisors

        1.9 org.springframework.aop.aspectj.annotation.BeanFactoryAspectJAdvisorsBuilder#buildAspectJAdvisors  解析切面类,构建advisors,存放到缓存中

        2.0 org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory#getAdvisor        -》 new InstantiationModelAwarePointcutAdvisorImp

    二、AOP 触发时机说明

        1、在没有循环依赖的情况下,AOP生成代理 是在 bean的初始化完成以后(属性赋值之后)

          1.1 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean() 

          1.2 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsAfterInitialization 

          1.3 org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessAfterInitialization 这里是bean的后置处理器的第九次调用,aop和事务都会在这里生存代理对象

          1.4 org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#wrapIfNecessary 

             根据当前bean找到匹配的 (一)中生成的advisor,匹配到了说明需要生成代理对象

          1.5 org.springframework.aop.framework.DefaultAopProxyFactory#createAopProxy 创建代理工厂,

            根据 当前bean是否实现接口,,是否设置ProxyTargetClass 属性 ,判断生成 jdk的代理工厂,还是cglib的代理工厂

            若我们  ProxyTargetClass 指定为false 且代理类是接口才会走jdk代理 否在我们还是cglib代理  ;;ProxyTargetClass 默认为false;

          1.6 JdkDynamicAopProxy ->Proxy.newProxyInstance(classLoader, proxiedInterfaces, this); 生成代理对象

            CglibAopProxy 生成代理

        2、存在循环依赖的情况下,AOP生成代理 是在 bean 实例化以后

    三、代理对象调用方法,进行增强

      以jdk动态代理为例:

      1. org.springframework.aop.framework.JdkDynamicAopProxy#invoke

        1.1 判断哪些方法不需要增强  (equals、hashcode 等方法无需增强)

        1.2 获取到目标对象

        1.3 找到适配到当前目标对象的所有的advisors;如果没有,,直接执行目标对象方法;如果有 先执行增强方法

        1.4 将目标对象的所有advisors 构造成一个 拦截器链一次执行, (说明:此处 使用的是 责任链模式) 这里用了责任链的设计模式,递归调用排序好的拦截器链

          执行顺序: @AfterTrrowing  @AfterReturning  @After  @Before 

      说明:jdk动态代理 本类方法 A 调用 B 不会走动态代理,,可以设置 expose属性

        1 jdk动态代理 底层使用的是 反射  InvocationHandler.invoke()方法,,生成的代理对象 实现了  接口  implements xxService.java

        2 cglib 动态代理底层使用的是 MethodInterceptor.interceptor()方法,生成的代理对象  继承了 被代理类,, extends xxAAAA.java  ;;底层使用的是 AMS

          效率问题:

          1.生成的代理的时候,,jdk 效率优于 cglib,因为 jdk生成一个文件,,cglib生成多个文件

          2. 调用的时候,,cglib优于 jdk,,因为 jdk 底层使用的是反射调用 ,cglib 是直接调用方法

      @EnableAspectJAutoProxy(proxyTargetClass = true,exposeProxy = true)

      proxyTargetClass = true 指定使用cglib动态代理,spring中如果实现了接口,默认使用jdk动态代理,未实现接口的情况下才使用cglib动态代理
      exposeProxy 将代理对象暴露到ThradLocal中,jdk动态代理中,同类中的A()方法,通过this.B()调用同类的B方法,AOP对B()方法不生效,因为此处的this获取的是
               类的对象,非代理对象,可以通过 AopContext.currentProxy()获取到代理对象调用B(),AOP会生效(此处需要设置exposeProxy = true)

          

          

  • 相关阅读:
    循环语句(2019年10月10号)
    (面试题)引用数据类型(2019年10月9日)
    引用数据类型(2019年10月9日)
    学车的录像,需要的拿走,比驾校实用。
    Laravel5.1 学习笔记1, 目录结构和命名空间(待修)
    PHP中的魔术方法和魔术常量
    php获取当地时间 time zone
    Windows7环境下Composer 安装包的Cache目录位置
    PHP 框架Laravel Eloquent 实现身份验证
    《CSS Mastery》读书笔记(4)
  • 原文地址:https://www.cnblogs.com/wl20200316/p/15994784.html
Copyright © 2020-2023  润新知