Spring AOP
在上一章节,笔者对Spring-Mybatis的核心思想做了详细介绍,目的是让读者能够更加清晰的认知Spring的全局生命周期,以及Spring是如何设计对外扩展的开放,本章将对Spring AOP的原理及源码进行详细说明。
Spring AOP应用
首先还是对Spring AOP的基本功能简单介绍。切面配置类
被增强的类
配置类
新建一个测试类
输出结果:
通过执行结果我们可以看到我们不需要修改任何原有的代码就可以改变代码的逻辑,其实在上一篇文章中笔者就已经对动态代理有所介绍,比如在Mybatis中的Mapper接口就是通过JDK动态代理,只不过我们的Mybatis代理需求相对复杂,而Spring AOP相对单一,因为Spring AOP是对自己内部的对象代理,也就是说Spring AOP是先装入Spring容器,在由其他的其他组件进行代理,而Mybatis和其恰好消防,Mybatis是先代理在装入Spring,所以我们在上一篇文章中在将代理对象整合到Spring中遇到了很多问题,如果读者对此没有印象建议回顾《Spring深度源码解析(七) Spring-Mybatis核心思想》。
Spring AOP源码解析
在对Spring应用做了简单介绍后,我们先思考一下如果我们自己实现一个SpringAOP,如何去实现呢,如何动态的去改变类的创建方式呢?在《Spring源码深度分析(六)》笔者提到,在对Spring实例化前后、初始化前后,Spring都做了循环后置处理器的处理提供对外扩展,再思考如果我们是对类进行代理,那么会采用CGLIB的方式进行代理,为什么SpringAOP实现了切面代理,我们关注这个注解
进入这个注解
可以看到这里又有这个@Import注解,@Import什么用我就不介绍了,笔者在Spring-Mybatis做了大量文章。
这里我们又看到了ImportBeanDefinitionRegistrar,这里我在啰嗦几句Spring提供了很多种对外的拓展方式,ImportBeanDefinitionRegistrar就是其中一种,如果自己定的类实现了它就可以获取工厂注册器。
@Override
public void registerBeanDefinitions(
AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
AnnotationAttributes enableAspectJAutoProxy =
AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
if (enableAspectJAutoProxy != null) {
if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
}
}
注意这段代码:
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
->registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry, null);
->registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
->registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
其实就是向我们的工厂注册了这个一个类AnnotationAwareAspectJAutoProxyCreator,我们点开这么类
可以看到这个类实现了BeanPostProcessor,说明这个类同样是后置处理器,既然这是后置处理器,就可以改变我们工厂内部的对象,既然能够改变我们的对象是不是就能将我们的某些对象进行代理?答案是肯定的,那么这就解惑了我在上文提出的Spring通过什么手段完成的代理,读者是不是觉得Spring的后置处理器很神奇啊,到哪都有它,好了我们对AnnotationAwareAspectJAutoProxyCreator做了简要分析,接下来将对Spring AOP做详细介绍。Spring AOP源码
首先我们将代码停留在doCreateBean(),断点采用的是被AOP增强的person类
然后这里的instanceWrapper为空,我们下一步,
看到我们的person对象已经创建成功,注意我们发现这里的person对象并没有被代理,而仅仅是被创建出来,为什么Spring没有在创建对象的时候进行拦截代理呢?道理很简单,我们在IOC的文章提出了Spring在创建对象后还需要执行属性注入,生命周期等步骤,如果我们提前将对象进行代理,我们能否对对象实施属性注入、生命周期这都不能确定。那么Spring是在哪里进行代理的呢?我们将代码停在属性注入的下面
发现并没有被代理,我们执行下一步
发现该对象已经被我们的CGLIB进行代理,那么在这段代码里面就进做了什么操作呢?我们跟踪下一这段代码:exposedObject = initializeBean(beanName, exposedObject, mbd);我们一路跟踪停在这里
然后点击去
循环我们的后置处理器获取我们所需要的AspectJAwareAdvisorAutoProxyCreator->postProcessAfterInitialization
然后我们再度将代码停在这里
看名字我们大概能猜到这里就是代理的关键代码,我们跟进下去
然后获取一些adviors
我们其实可以猜到,这里就是获取我们的AspectTest的信息
好了,既然我们获取了我们的代理配置,那么就要开始对我们所符合标准的代理对象进行代理了
进createProxy方法在-》 proxyFactory.getProxy(getProxyClassLoader());
很明显这里就是真正创建代理的角色了,继续跟踪代码
这里就是根据什么样的需求创建什么样的代理方式,注意这里仅仅只是方式,并不是真正创建代理对象的逻辑,比如我们这里代理的是类,那么会选择CGLIB的方式
然后我们再回到前面的代码
可以看到createAopProxy()获取的就是我们创建代理的方式,至于我们的getProxy(),笔者就不多写了,内部就是如何使用cglib增强的代码,笔者在@Configuration中对如何通过cglib代理对象做了大量分析,这里就略过,那么我们已经知道了Spring AOP的代理流程,那么其实还缺少一样东西,不知读者是否发现我们的adviors并不知道什么时候就存在了呢?接下来我们就去解答这个问题,首先我们将代码停在doCreateBean():的上面,doCreateBean()我们在IOC创建Bean进行了详细介绍,就是开始创建Bean,那么对adviors的操作明显就是在创建Bean之前就完成了,为了验证我们将代码跟进:
进入代码
注意这个getBeanPostProcessors(),一共有九个,这里会循环获取
找到我们AOP注册的后置处理器,然后点进去
注意postProcessBeforeInstantiation,其实就是实例化之前的操作,Spring的命名十分规范,我们在上文介绍了这是在doCreateBean之前操作的,所以称为实例化之前,我们停留在这里
点击去shouldSkip,继续跟踪跟踪
然后进入
然后进入会发现这个buildAspectJAdvisors方法很长,我们直接找到关键代码
可以看到我们就是用过this.advisorFactory.getAdvisors(factory);这句代码获取我们切面的方法,我们在进入getAdvisors(factory)
@Override
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory maaif) {
final Class<?> aspectClass = maaif.getAspectMetadata().getAspectClass();
final String aspectName = maaif.getAspectMetadata().getAspectName();
validate(aspectClass);
// We need to wrap the MetadataAwareAspectInstanceFactory with a decorator
// so that it will only instantiate once.
final MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
new LazySingletonAspectInstanceFactoryDecorator(maaif);
final List<Advisor> advisors = new LinkedList<Advisor>();
for (Method method : getAdvisorMethods(aspectClass)) {
Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName);
if (advisor != null) {
advisors.add(advisor);
}
}
// If it's a per target aspect, emit the dummy instantiating aspect.
if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
advisors.add(0, instantiationAdvisor);
}
// Find introduction fields.
for (Field field : aspectClass.getDeclaredFields()) {
Advisor advisor = getDeclareParentsAdvisor(field);
if (advisor != null) {
advisors.add(advisor);
}
}
return advisors;
}
其实这里面就是通过反射的方式获取我们的方法,返回后在存起来交给我们后面对被代理类进行增强,至此Spring AOP源码分析到此为止,Spring 事物其实和我所提到Spring源码第七章和本章思想大致一致,笔者就不在对事物进行单独叙述了,下一章将会更新SpringMVC。