AOP是什么怎么用就不在这里赘述了,这里就从源码看一下AOP的实现。
1、Spring 如果要支持注解形式的AOP,就要在配置文件中配置<aop:aspectj-autoproxy/>。
这里简单说一下Spring解析标签的过程:Spring中将标签分为默认标签(import、alias,bean和beans)和自定义标签。
<aop:aspectj-autoproxy/>属于自定义标签,解析过程为当读取到这个标签时,会根据命名空间去找到对应的自定义标签处理器AopNamespaceHandler,AopNamespaceHandler会执行init()方法。在这里会将AspectJAutoProxyBeanDefinitionParser进行注册。而AspectJAutoProxyBeanDefinitionParser正是专门解析"aspectj-autoproxy"标签的解析器。
AspectJAutoProxyBeanDefinitionParser实现了BeanDefinitionParser接口,会执行parse()对标签进行解析。这个parse()中AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element)这个方法,从名字就可以看出是用来注册自动代理创建器,我们具体看下这个方法内做了什么。
一共做了三件事:
1)注册或者升级AnnotationAwareAspectJAutoProxyCreator
2)对于proxy-target-class以及expose-proxy 属性的处理
3)注册组件并通知,便于监听器做进一步处理
1)注册或者升级AnnotationAwareAspectJAutoProxyCreator
先看第一件,跟踪代码可依次走到如下两个方法。主要功能点就是注册AnnotationAwareAspectJAutoProxyCreator。
具体注册过程,会先判断自动代理创建器是否已经存在。
1)不存在,直接创建新的创建器。
2)若存在
1)且与想要创建的新创建器相同,不进行操作。
2)且与想要创建的新创建器不同,就要判断两个创建器的优先级,如果新创建器优先级高,则进行新创建器的创建,否则不操作还是用原来创建器。
2)对于proxy-target-class以及expose-proxy 属性的处理
这个方法实际就是读取配置文件并将属性赋值的过程。
说一下这个两个属性作用。
1)proxy-target-class
默认情况下,"proxy-target-class"默认是"false",当被代理类实现了至少一个接口,Spring默认使用JDK动态代理,当被代理类没有实现接口时使用CGLIB代理,但是如果想强制任何时候都使用CGLIB代理,那么需要如下配置:
<aop : aspectj-autoproxy proxy-target-class="true"/>
2)expose-proxy
如下例子可以说明这个属性。
有时候目标对象内部的自我调用将无法实施切面中的增强,此处的this 指向目标对象,因此调用this.b()将不会执行b事务切面,即不会执行事务增强。
为了解决这个问题,配置:
<aop:aspectj-autoproxy expose-proxy=”true”/>
然后将以上代码中的“this.b()”修改为“ ((AService) AopContext.currentProxy()).b()”即可。
通过以上的修改便可以完成对a和b方法的同时增强。
3)注册组件并通知,便于监听器做进一步处理
这一步是注册组件,对于AOP实现没有什么关联。
2、在上面完成了AnnotationAwareAspectJAutoProxyCreator的注册创建,这个类也是实现AOP的关键,我们看这个类到底怎么实现的AOP。可以看到AnnotationAwareAspectJAutoProxyCreator类实现了BeanPostProcessor接口。
BeanPostProcessor常常被称为后置处理器,作用是在Bean对象在实例化和依赖注入完毕后,在显示调用初始化方法的前后添加我们自己的逻辑。流程如下:
Spring IOC容器实例化Bean--->调用BeanPostProcessor的postProcessBeforeInitialization方法--->调用bean实例的初始化方法--->调用BeanPostProcessor的postProcessAfterInitialization方法
AnnotationAwareAspectJAutoProxyCreator实现BeanPostProcessor 后,当Spring加载Bean时会在初始化后调用其父类AbstractAutoProxyCreator重写的postProcessAfterInitialization方法,对生产出的bean进行包装。
具体看下AbstractAutoProxyCreator重写的postProcessAfterInitialization方法,其中wrapIfNecessary()方法是我们要关注的。
看注释相信大家也大概明白这个方法的逻辑了,无非是先判断这个类是不是需要增强,如果需要增强就创建代理。这里我们主要看getAdvicesAndAdvisorsForBean()和createProxy()这两个方法。
1)getAdvicesAndAdvisorsForBean()
下面实际做了两件事,获取所有的增强器以及寻找所有增强器中适用于这个bean 的增强器。
我们先来看一下怎么获取的所有增强器。主要是分别获取了xml配置中的增强器和注解中的增强器。
我们主要看一下怎样获取注解形式的增强器,也就是buildAspectJAdvisors()这个方法,图片里有注释,简单来说就是拿到所有beanName,遍历beanName找到有@Aspect注解的类,然后处理这些有@Aspect注解的类的提取增强器。
提取增强器主要是getAdvisors()这个方法,我们接下来看下这个方法具体实现。
1)getPointcut()拿到切点信息
2)new InstantiationModelAwarePointcutAdvisorImpl()封装生成增强器。
1)getPointcut()拿到切点信息
切点信息获取其实也是获取方法上注解的信息,不详细解释了。
2)new InstantiationModelAwarePointcutAdvisorImpl()封装生成增强器。
可以看出来如果是懒加载,则先看到这可能还是不能看出来我们熟悉的内容,别急,往下看,看instantiateAdvice()方法。
我们可以看到before、after这些我们熟悉的切面注解了,spring会根据注解生成不同类型的增强器,常说的前置增强、后置增强、环绕增强。
至此我么我们知道了spring怎么获取所有的增强器。那么返回之前我们的地方。拿到所有增强器后,就是找出适用这个bean的增强器,其实就是找到符合我们配置的通配符的增强器。
至此我们分析完了获取这个类增强器的方法。如果这个类存在需要增强器,就要创建代理,也就是createProxy()。
这个方法就为我们创建了代理类,当实际调用时是代理类替代目标类为我们执行了方法,当然就把我们的切面方法也执行了。
BeanPostProcessor