一、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 增强过程