SpringAOP源码解析(下)

ProxyFactory选择jdk或者cglib动态代理的原理

ProxyFactory在生成代理对象之前需要先决定到底是使用cglib技术还是jdk动态代理 在上篇中有讲到cblib技术----把当前类当作一个父类,生成的代理对象的类型和当前类一样

java 复制代码
UserService target = new UserService();
//1.使用cglib技术,构造一个增强器
Enhancee enhancer = new Enhancer();
//2.定义代理逻辑
enhancer.setCallBacks(new CallBack[]
{new MethodInterceptor(){
@Override
public Object intercept(Object o,Method method,Object[] objects,MethodProxy methodPoxy) throws Throwable{
System.out.println("before...");
Object result = methodProxy.invoke(target, objects);  
  System.out.println("after...");  
  return result;  
 }  
}});  
  
// 动态代理所创建出来的UserService对象  
UserService userService = (UserService) enhancer.create();  
  
// 执行这个userService的test方法时,就会额外会执行一些其他逻辑  
userService.test();
}

}}
graph TD ProxyFactory的对象 --> optimize为true,或proxyTargetClass为true,或用户没有给ProxyFactory对象添加interface --> ProxyFactory对象获取目标类 --> 判断目标类是否为空 -->为空抛出AopConfigException-->不为空判断目标类是否是接口-->是接口直接使用jdk动态代理-->不是接口则使用cglib技术

代理对象创建过程

JdkDynamicAopProxy

  1. 在构造JdkDynamicAopProxy对象的时候,会先拿到被代理对象自己实现的接口,并且额外的 增加SpringProxy,Advised,DecoratingProxy三个接口,组合成一个Class[],并赋值给proxiedInterfaces属性
  2. 检查接口中是否定义了equals(),hashcode()方法。
  3. 执行Proxy.newProxyInstance(classLoader, this.proxiedInterfaces, this),得到代理对象,JdkDynamicAopProxy作为InvocationHandler,代理对象在执行某个方法时,会进入到JdkDynamicAopProxy的**invoke()**方法中

ObjenesisCglibAopProxy

  1. 创建Enhancer对象
  2. 设置Enhancer的superClass为通过ProxyFactory.setTarget()所设置的对象的类
  3. 设置Enhancer的interfaces为通过ProxyFactory.addInterface()所添加的接口,以及SpringProxy、Advised、DecoratingProxy接口
  4. 设置Enhancer的Callbacks为DynamicAdvisedInterceptor
  5. 最后创建一个代理对象,代理对象在执行某个方法时,会进入到DynamicAdvisedInterceptor的intercept()方法中

代理对象执行过程

  1. 在使用ProxyFactory创建代理对象之前,需要往ProxyFactory先添加Advisor
  2. 代理对象在执行某个方法时,会把ProxyFactory中的Advisor拿出来和当前正在执行的方法进行匹配筛选
  3. 把和方法所匹配的Advisor适配成MethodInterceptor
  4. 把和当前方法匹配的MethodInterceptor链,以及被代理对象、代理对象、代理类、当前Method对象、方法参数封装为MethodInvocation对象
  5. 调用MethodInvocation的proceed()方法,开始执行各个MethodInterceptor以及被代理对象的对应方法
  6. 按顺序调用每个MethodInterceptor的invoke()方法,并且会把MethodInvocation对象传入invoke()方法
  7. 直到执行完最后一个MethodInterceptor了,就会调用invokeJoinpoint()方法,从而执行被代理对象的当前方法

各注解对应的MethodInterceptor

  • @Before 对应的是AspectJMethodBeforeAdvice,在进行动态代理时会把AspectJMethodBeforeAdvice转成MethodBeforeAdviceInterceptor

    • 先执行advice对应的方法
    • 再执行MethodInvocation的proceed(),会执行下一个Interceptor,如果没有下一个Interceptor了,会执行target对应的方法
  • @After 对应的是AspectJAfterAdvice,直接实现了MethodInterceptor

    • 先执行MethodInvocation的proceed(),会执行下一个Interceptor,如果没有下一个Interceptor了,会执行target对应的方法
    • 再执行advice对应的方法
  • @Around 对应的是AspectJAroundAdvice,直接实现了MethodInterceptor

    • 直接执行advice对应的方法,由@Around自己决定要不要继续往后面调用
  • @AfterThrowing 对应的是AspectJAfterThrowingAdvice,直接实现了MethodInterceptor

    • 先执行MethodInvocation的proceed(),会执行下一个Interceptor,如果没有下一个Interceptor了,会执行target对应的方法
    • 如果上面抛了Throwable,那么则会执行advice对应的方法
  • @AfterReturning 对应的是AspectJAfterReturningAdvice,在进行动态代理时会把AspectJAfterReturningAdvice转成AfterReturningAdviceInterceptor

    • 先执行MethodInvocation的proceed(),会执行下一个Interceptor,如果没有下一个Interceptor了,会执行target对应的方法
    • 执行上面的方法后得到最终的方法的返回值
    • 再执行Advice对应的方法

AbstractAdvisorAutoProxyCreator

DefaultAdvisorAutoProxyCreator的父类是AbstractAdvisorAutoProxyCreator。

AbstractAdvisorAutoProxyCreator 非常强大以及重要,只要Spring容器中存在这个类型的Bean,就相当于开启了AOP,AbstractAdvisorAutoProxyCreator实际上就是一个BeanPostProcessor,所以在创建某个Bean时,就会进入到它对应的生命周期方法中,比如:在某个Bean初始化之后,会调用wrapIfNecessary()方法进行AOP,底层逻辑是,AbstractAdvisorAutoProxyCreator会找到所有的Advisor,然后判断当前这个Bean是否存在某个Advisor与之匹配(根据Pointcut),如果匹配就表示当前这个Bean有对应的切面逻辑,需要进行AOP,需要产生一个代理对象。

@EnableAspectJAutoProxy

这个注解主要就是往Spring容器中添加了一个AnnotationAwareAspectJAutoProxyCreator类型的Bean。 AspectJAwareAdvisorAutoProxyCreator 继承了AbstractAdvisorAutoProxyCreator ,重写了findCandidateAdvisors()方法,AbstractAdvisorAutoProxyCreator 只能找到所有Advisor类型的Bean对象,但是AspectJAwareAdvisorAutoProxyCreator 除开可以找到所有Advisor类型的Bean对象,还能把@Aspect注解所标注的Bean中的@Before等注解及方法进行解析,并生成对应的Advisor对象。

所以,我们可以理解@EnableAspectJAutoProxy,其实就是像Spring容器中添加了一个AbstractAdvisorAutoProxyCreator类型的Bean,从而开启了AOP,并且还会解析@Before等注解生成Advisor。

相关推荐
蝎子莱莱爱打怪1 小时前
Hadoop3.3.5、Hbase2.6.1 集群搭建&Phoenix使用记录
大数据·后端·hbase
David爱编程1 小时前
并发编程三大特性全解析:原子性、可见性、有序性,一文讲透!
java·后端
你的人类朋友2 小时前
git常见操作整理(持续更新)
前端·git·后端
你的人类朋友2 小时前
git中的Fast-Forward是什么?
前端·git·后端
黑客影儿3 小时前
Go特有的安全漏洞及渗透测试利用方法(通俗易懂)
开发语言·后端·安全·web安全·网络安全·golang·系统安全
追逐时光者4 小时前
一款基于 Ant Design 设计语言实现、漂亮的 .NET Avalonia UI 控件库
后端·.net
笃行3506 小时前
从零开始:SpringBoot + MyBatis + KingbaseES 实现CRUD操作(超详细入门指南)
后端
该用户已不存在7 小时前
这几款Rust工具,开发体验直线上升
前端·后端·rust
用户8356290780517 小时前
C# 从 PDF 提取图片教程
后端·c#
L2ncE7 小时前
高并发场景数据与一致性的简单思考
java·后端·架构