AspectJ介绍:AspectJ是一个java实现的AOP框架,它能够对java代码进行AOP编译(一般在编译期进行),让java代码具有AspectJ的AOP功能(当然需要特殊的编译器)
AspectJ的织入方式及其原理概要:我们仍需要了解AspectJ应用到java代码的过程(这个过程称为织入),对于织入这个概念,可以简单理解为aspect(切面)应用到目标函数(类)的过程。对于这个过程,一般分为动态织入和静态织入,动态织入的方式是在运行时动态将要增强的代码织入到目标类中,这样往往是通过动态代理技术完成的,如Java JDK的动态代理(Proxy,底层通过反射实现)或者CGLIB的动态代理(底层通过继承实现),Spring AOP采用的就是基于运行时增强的代理技术,这点后面会分析,这里主要重点分析一下静态织入,ApectJ采用的就是静态织入的方式。ApectJ主要采用的是编译期织入,在这个期间使用AspectJ的acj编译器(类似javac)把aspect类编译成class字节码后,在java目标类编译时织入,即先编译aspect类再编译目标类(即编译后的字节码包含了aspect代码)
ApectJ编译方式:当然除了编译期织入,还存在链接期(编译后)织入,即将aspect类和java目标类同时编译成字节码文件后,再进行织入处理,这种方式比较有助于已编译好的第三方jar和Class文件进行织入操作
spring aop和aspectj的关系:spring aop 更关注于与ioc的结合,底层采用动态编译即jdk动态代理和cglib,并按照aspectj风格进行aop的开发(比如设置apsectj注解,定义pointcut advice advisor等)
InstantiationAwareBeanPostProcessor 在BeanPostProcessor基础上增加 实例化前后的扩展点(BeanPostProcessor是在bean初始化前后进行操作)
AspectJ的逻辑
1.在初始化之后开始调用,就是解析某个类是否需要变成代理
2.判断是否需要代理的原则,找到这个类是否有对应的advisor,如果有就是需要变成代理
3.如何去寻找advisor,针对于asepctJ是去寻找对应的@AsepctJ的注解类,然后获取所有的adviosr 然后解析advisor上面的pointcut,看看ponitcut是否匹配目前的类或者方法
4.当存在advisor之后在advisor集合里面第一位添加ExposeInvocationInterceptor,该类是作为调用链的头部 可以方便的获取调用链上下文
5.不论是jdk还是cglib调用的都是ReflectiveMethodInvocation的process方法,即spring把advisor转换成MethodInterceptor
该方法内部就是循环调用MethodInterceptor,当调用链结束了才调用 真正方法
整个逻辑类似递归调用。
6.依靠proxyfactory创建代理对象
@Asepctj的aop生成源码解析:https://www.jianshu.com/p/58e0828c062c
ProxyFactoryBean的逻辑
和proxyfactoryBean的aop源码解析:https://www.jianshu.com/p/e376014e6795
之所以在源码中创建代理采用proxyFactory 而不是AspectJrpoxyFactory是因为这是父类 如果AspectJrpoxyFactory,会导致不适配其他类型,而且proxyfactory 有通用性,因为他们创建aopproxy的方法都是一样 只是收集advice不一样,而advice已经被收集到了
代理中遇到调用返回this方法会直接退换成proxy本身
cglib在创建proxy过程通过proxyfilter,来分配某些方法对应哪个callback,然后运行的执行哪个callback的intercept方法(不同的interceptor方法就是不同的callback方法的具体逻辑执行者)
springAop的更简单的总结:收集advisor 创建代理对象 把adviosr 转换成methodinterceptor 最终通过ReflectiveMethodInvocation(jdk)或者CglibMethodInvocation(其继承了ReflectiveMethodInvocation cglib)去执行这些interceptor,
ReflectiveMethodInvocation 逻辑:当我们只想对应的Interceptor要执行的内容,如果我们还需要只想下一步,就调用this.process,就又回到这个ReflectiveMethodInvocation的process方法
CGLIB:是在proxyproxy创建的时候进行method的intercept的分配和缓存
JDK:jdk 是在proxy第一次调用方法的进行method的intercept的分配和缓存
CglibMethodInvocation改写ReflectiveMethodInvocation的invokeJoinpoint方法,与使用反射相比,性能略有改善在调用公共方法时调用目标。(即JDK是通过method的invoke方法 而cglib通过MethodProxy的invoke)