SPRING的AOP源码解析

一、AOP 入口

通过扫描注解@EnableAspectJAutoProxy(proxyTargetClass =true,exposeProxy = true)注册了AOP 入口类,具体看看注解里面的@Import(AspectJAutoProxyRegistrar.class),我们知道@Import注解的作用就是将AspectJAutoProxyRegistrar引入到spring容器中。

由于该类实现了ImportBeanDefinitionRegistrar,所以在ConfigurationClassPostProcessor类中,也就是将所有的加载解析beanDefinition的时候,会执行到这个方法,也就是这个时候将跟代理相关的类AnnotationAwareAspectJAutoProxyCreator解析承了beanDefinition,最终加入到了spring容器中。

有了AnnotationAwareAspectJAutoProxyCreator这个类之后,也就具备了生成代理的条件

二、是否生成代理

当一个bean 实例化完成后,初始化的时候,会判断该bean 是否生成代理,AOP 的入口,如图:

这是一个BeanPostProcessor 接口的运用,initializeBean 方法我们都知道是一个 bean 实例化完成后做的操作,而这个代理实例生成也是在bean 实例化完成后做的操作,其核心代码如下

在下面这个方法里面就是判断当前bean 是否有切面advisor,如果有切面就会走到createProxy
方法,生成代理对象然后返回

其实寻找当前bean 的切面简单来说就两步:

1、从spring 中找所有的切面

2、找到拦截当前bean 的切面

当advisors这个数组不为空时,就会往下走,走到createProxy 方法里面,这个方法就会生成bean
的代理实例。

从spring 中找所有切面, 先找到所有的beanDefinition 对象对应的beanName, 拿到对应的Class 对象,判断该类上面是否有@Aspect 注解,如果有则是我们要找的, 循环该Class 里面的除了@PointCut 注解的方法,找到方法上面Around.class,Before.class,After.class,AfterReturning.class, AfterThrowing.class 注解,并且把注解里面的信息,比如表达式,argNames,注解类型等信息封装成对象 AspectJAnnotation,然后创建pointCut 对象,把注解对象中的表达式设置到pointCut 对象中,然后就是创建Advice 对象,根据不同的注解类型创建出不同的Advice 对象,对象 如下:AspectJAroundAdvice,AspectJAfterAdvice, AspectJAfterThrowingAdvice,AspectJMethodBeforeAdvice, AspectJAfterReturningAdvice 最终把注解对应的Advice 对象和pointCut 对象封装成 Advisor 对象。 找到拦截当前bean 的切面 从收集到的所有切面中,每一个切面都会有pointCut 来进行模块匹配,其实这个过程就 是一个匹配过程,看看pointCut 表达式中的内容是否包含了当前bean,如果包含了,那么这 个bean 就有切面,就会生成代理。

创建代理的过程:


1、创建代理工厂对象ProxyFactory
2、切面对象重新包装,会把自定义的MethodInterceptor 类型的类包装成Advisor
切面类并加入到代理工厂中
3、根据proxyTargetClass 参数和是否实现接口来判断是采用jdk 代理还是cglib 代

4、创建代理对象,并且把代理工厂对象传递到jdk 和cglib 中,注意这里的代理对象和
jdk 类和cglib 类是一一对应的。
代理实例的调用
上面我们已经创建出来了代理对象了,现在是拿到代理对象调用,以jdk 动态代理为例,
cglib 是一样的调用逻辑。
当发生代理对象调用时,肯定会调用到实现了invocationHandler 接口的类,这个类就
是:JdkDynamicAopProxy,必定会调用到该类的invoke 方法

从代理工厂中拿到切面,并且跟当前被代理类和当前被调用方法匹配,如果匹配就返回切
面中的advice 对象,这就是advice 执行链

获取到这个执行链后,判断如果执行链为空,则直接反射调用方法,说明该方法没被拦截,
如果不为空就会有一个链式调用过程。

在ReflectiveMethodInvocation 中维护了执行链数组和数组索引,通过索引获取到数组里面的advice,然后调用,如果第一个advice 调用到了beforeAdvice,如下:

BeforeAdvice 首先会调用自己advice 对象中的method 对象,而这个method 对象就是有@Before 注解的方法,我们通过解析方法上面的注解类型生成advice 对象时把对应的method 对象封装到了advice 对象中,所以这里就只要反射调用method 对象即可。掉完后,这里有一个mi.proceed()这个方法又会回到ReflectiveMethodInvocation 这个类中。

这时候索引又会+1,然后从链中后去下一个advice,然后下一个advice 调用完后再
mi.proceed()又会接着调用,就这样形成了一个链式调用过程。直到数组链中全部调用
完后会调用到具体的joinPoint 方法,如下:

当判断当前索引==执行链数组大小时就会调用到被代理方法。完成aop 增强过程

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值