SpringAOP源码分析
目录
写在前面
本文简介:今天我们主要分析springAOP的源码流程,因为博主本人习惯于使用AspectJ和注解的方式使用AOP,因此本次的分析是基于@EnableAspectJAutoProxy注解和cglib动态代理的AOP,其实JDK的动态代理基本类似,本文也会有所涉及,温馨提醒,源码分析流程很长,慎入,需要看大概流程的小伙伴直接看总结部分即可。
如何分析SpringAOP源码?
其实我们要分析spring某些功能的源码只需要抓住以下三个点。
1.我们使用这个功能时,往IOC容器中添加了什么东西,这个东西是什么?
2.我们往IOC容器添加的东西是什么时候执行的?
3.我们往IOC容器中添加的东西是怎么进行执行的,执行的结果是什么?
我们后续的源码分析将会基于以上三个问题,希望大家带着问题进行思考。
源码分析
@EnableAspectJAutoProxy注解
我们在配置类上加上@EnableAspectJAutoProxy或者在配置文件中加上< aop:aspectj-autoproxy >< /aop:aspectj-autoproxy>注解AOP功能就生效了,我们不添加该注解,AOP将无法生效。所以该注解是我们研究AOP功能的关键,我们点进这个注解看一看。
该注解使用了@Import(AspectJAutoProxyRegistrar.class),@Import注解将会帮助我们往IOC容器中自定义导入组件,可以直接传入组件的class、一个ImportSelector的子类、或者是ImportBeanDefinitionRegistrar。这里导入的AspectJAutoProxyRegistrar是ImportBeanDefinitionRegistrar的子类
他实现了一个registerBeanDefinitions方法,会在IOC容器创建时往IOC容器中注册组件信息。我们在该方法打上断点。debug执行
代码停在了该行,我们注意下方法调用栈
我们实际是在IOC容器创建的Refresh方法中调用了invokeBeanFactoryPostProcessors(beanFactory)方法一步一步执行过来的
ok,知道该方法在IOC容器Refresh方法执行的位置后,我们回到我们的第一张图registerBeanDefinitions()方法
我们跟进这个方法,我们来到了AopConfig的registerOrEscalateApcAsRequired()方法
该放方法的主要步骤如图
该方法中的常量AUTO_PROXY_CREATOR_BEAN_NAME =
该方法的cls为
所以这一步实际上我们是往BeanDefinitionRegistry中注册了一个Bean,bean的名字为org.springframework.aop.config.internalAutoProxyCreator,bean的类型为:org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator
本步流程总结
使用AspectJAutoProxyRegistrar给我们的BeanDefinitionRegistry中注册一个bean,bean的name为:internalAutoProxyCreator内部自动代理创建器,bean的类型为AnnotationAwareAspectJAutoProxyCreator。
AnnotationAwareAspectJAutoProxyCreator
上一步我们往IOC容器中注册了AnnotationAwareAspectJAutoProxyCreator信息,那么我们注册的这个东西到底有什么用呢?我们进入这个类进行查看
这是该类的继承结构,我们到AbstractAutoProxyCreator中,我们发现该类是BeanFactoryAware和SmartInstantiationAwareBeanPostProcessor接口的是实现类,SmartInstantiationAwareBeanPostProcessor是BeanPostProcessor接口的子接口,BeanFactoryAware是Aware的子接口。
BeanPostProcessor会在对象的初始化方法进行拦截操作
BeanFactoryAware属于XXXAware类接口有SetXXX方法,能往我们的组件中注入IOC容器底层的组件。
因此我们找到AnnotationAwareAspectJAutoProxyCreator类中上述方法的位置,并且打上断点。
上述接口方法的分布如下,我们在对应位置打上断点Debug运行
代码停在了AbstractAdvisorAutoProxyCreator的setBeanFactory()方法处
首先我们调用了super的setBeanfactory中往该对象中注入了BeanFactory
继续往下看,我们调用了初始化beanFacroy的方法,我们跟进查看
我们将beanFactory进行封装,传给了aspectJAdvisorsBuilder。
然后我们返回,发现回到了AbstractAutowireCapableBeanFactory类中,该类是我们创建Bean并将其保存在IOC容器中的核心业务Bean,里面有我们的创建bean,属性注入,后置处理器,初始化方法等所有业务逻辑。
看到这里我们就明白了,我们上一步注册好我们的AnnotationAwareAspectJAutoProxyCreator之后,这一步将其加入到了容器中。这一步刚好是refresh方法中的registerBeanPostProcessors方法,刚好在上一步后面。
本步流程总结
上一步我们将AnnotationAwareAspectJAutoProxyCreator注册到BeanDifinitionRegistry中后,在refresh的registerBeanPostProcessors方法中,我们将其加入了IOC容器中。
AOP业务方法执行
上一步我们将AnnotationAwareAspectJAutoProxyCreator加入到IOC容器中后,我们知道AnnotationAwareAspectJAutoProxyCreator是BeanPostProcessor的实现类,因此将会在我们Bean的初始化前后对bean进行操作,因此我们给切点类Bean的构造器上打上断点,我们查看切点类Bean是如何创建的。
第一步我们在refresh()方法中调用了finishBeanFactoryInitialization()方法,从该方法上面的注释也能看出,该方法是实例化所有剩余的Bean
我们跟进这个方法,我们来到了preInstantiateSingletons()方法,
该方法先获取出所有Bean的name,然后遍历name集合,选出!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()不是抽象,是单例的并且不是懒加载的bean进行获取,调用getBean方法
getBean方法–>>doGetBean() -->>getSingleton()–>>createBean()
然后我们停在了一个叫做resolveBeforeInstantiation()实例化前处理方法,这方法后续是真正的创建Bean的方法,但是如果当前方法返回值不为空我们就直接返回了,这说明我们希望做一些事情,看看能不呢直接返回需要的Bean而不是去创建这个Bean,我们继续跟进这个方法
我们来到了postProcessBeforeInstantiation()方法,这个方法是属于SmartInstantiationAwareBeanPostProcessor接口的,该方法会在对象创建前进行处理,在这里尝试创建代理对象进行返回,但是我们并不满足当前条件,改方法直接返回null
在创建bean之前我们没有实现返回代理对象的操作,我们的代码停在了创建对象之后的postProcessAfterInitialization方法,改方法调用了wrapIfNecessary()包装对象如果需要的话;方法,我们跟进去看看
该方法先判断当前bean是否为空啊、是否已经进行过增强、是否需要跳过等判断。
最终我们停在了这一步,我们跟进去看看
我们发现实际上调用了aspectJAdvisorsBuilder.buildAspectJAdvisors()去创建我们的增强器将其返回
然后我们advisedBeans已经增强bean中标准当前bean的增强情况为True,调用了createProxy()将我们bean,方法,参数,增强器等内容传入了进去。
我们进入到createProxy方法,发现他先创建了一个ProxyFactory,然后将我们的this对象封装进去了,然后将我们的specificInterceptors解析为Advisor[] advisors,实际上就是对我们的Interceptor进行包装this.advisorAdapterRegistry.wrap(allInterceptors.get(i));
最终调用了proxyFactory.getProxy(getProxyClassLoader());,我们继续跟进
调用了createAopProxy()方法,我们继续进入getAopProxyFactory().createAopProxy(this);方法
终于我们看到了我们代理对象的创建代码,spring会帮我们进行判断如果是实现了接口的情况会生成jdk代理,否则给我们生成Cglib动态代理对象。
最终我们将我们生成的cglib代理对象进行返回。
本步总结
我们在创建切点类的时候,会通过BeanPostProcessor的postProcessAfterInitialization的将我们的bean对象封装为代理对象,如果我们使用的是实现接口的方式,那么生成的是jdk的动态代理。如果我们使用的是aspectJ的方式,那么生成的将是Cglib的动态代理。
代理对象的执行过程
上一步我们生成了我们的动态代理对象,然后我们需要看看我们代理对象是如何执行切点方法的,我们在切点方法上加上一个断点。
我们的方法停在了 CglibAopProxy 的getInterceptorsAndDynamicInterceptionAdvice()方法,他返回了一个集合对象,我们跟进这个方法
我们发现他先想从缓存中获取cached,如果从缓存中获取不到,那么将调用getInterceptorsAndDynamicInterceptionAdvice方法,我们跟进这个方法
该方法内部先创建了一个和我们的增强器数组一样大小的集合,然后遍历我们的增强器
该方法内部的核心代码就是如下两个将 advisor 都转换为MethodInterceptor类型,然后将其加入集合中进行返回。
实际上将advisor转为MethodInterceptor对象就是判断如果直接是MethodInterceptor的类型,那么加入集合,否则使用AdvisorAdapter增强适配器将其包装为MethodInterceptor再加入集合。
那么我们的MethodInterceptor链就创建好了,实际上是将我们的增强器封装成方法拦截链而已。
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
这是我们的业务执行的核心方法,将我们的执行方法对象和方法信息,参数即拦截器链统统传入。我们来看看这个方法的执行。
我们当前拦截器的顺序为
然后proceed方法的执行过程如下
currentInterceptorIndex的下标代表当前已经执行完到哪个拦截器了,默认为-1,然后如果currentInterceptorIndex变为拦截器的的集合的size - 1时将会调用invokeJoinpoint()即切点对象的方法,我们分析一下执行流程。
第一次currentInterceptorIndex自增为0,执行ExposeInvocationInterceptor的invoke方法,进入invoke方法
我们发现调回了proceed方法。
第二次执行proceed方法:currentInterceptorIndex自增为1,执行AspectJAfterThrowingAdvice的invoke方法,进入invoke方法(不知道你是否有疑惑,为什么先执行的时afterThrowing方法,有疑惑就对了,我们继续往后看)
进入invoke方法,我们发现又是先执行proceed方法,发生异常才执行异常增强。我们继续去proceed方法
第三次执行proceed方法:currentInterceptorIndex自增为2,执行AspectJAfterReturnAdvice的invoke方法,进入invoke方法
我们发现invoke方法时先执行,如果没有异常就执行返回通知,那么有异常呢?这里也没有trycatch语句啊,大家不要忘了,我们后续的方法调用,是在第二个的try块里面执行的,所以有异常将会被捕获到那里执行,也就是没有异常正常返回通知,有异常异常通知。现在大家是不是有点眉目了呢?
第三次执行proceed方法:currentInterceptorIndex自增为3,执行AspectJAfterAdvice的invoke方法,进入invoke方法
该方法是直接先调用proceed方法,并且方法无论如何都会执行后置增强代码。(写spring的大佬简直太牛了,我本来以为AOP是通过嵌套try catch finally的代码实现的执行顺序,没想到是这样的!)
第四次执行proceed方法:currentInterceptorIndex自增为4,执行AspectJBeforerAdvice的invoke方法,进入invoke方法
我们发现before的增强处理是先执行前置增强方法,再执行proceed方法
第四次执行proceed方法:currentInterceptorIndex起始即为4,执行切点方法然后返回。
到这里大家应该明白了为什么我们AOP的执行流程是下面的情况
正常流程:前置通知-业务方法-后置通知-返回通知
异常流程:前置通知-业务方法-后置通知-异常通知
我们逆序调用我们的增强业务,将前一个拦截链先压入栈中,待方法弹栈结果决定当前方法的执行情况(膜拜写spring的大佬)
在方法链的调用过程中实际上用到了责任链的设计模式。
本步总结
这一步我们实际上是将我们的Advisors增强器包装为MethodInterceptor拦截器,然后通过责任链的设计模式,实现对我们业务方法的增强处理。
全文总结
总结
1.在BeanDefinitionRegistry中注册 AnnotationAwareAspectJAutoProxyCreator
在Refresh()方法的dnvokeBeanFactoryPostProcessors()方法中通过@EnableAspectJAutoProxy
注解我们往IOC容器中注册了 AnnotationAwareAspectJAutoProxyCreator 的信息
2.将AnnotationAwareAspectJAutoProxyCreator加入到IOC容器中
在Refresh()方法中的 registerBeanPostProcessors()方法中,将我们的AnnotationAwareAspectJAutoProxyCreator
加入到了IOC容器中,并且创建了aspectAdvisorBuilder对象。
3.获取代理对象
在refresh()方法中的finishBeanFactoryInitialization()方法里面我们通过AnnotationAwareAspectJAutoProxyCreator后置处理器的后置处理方法,
我们会判断组件是否需要进行增强处理,如果需要则调用了aspectJAdvisorsBuilder.buildAspectJAdvisors()
方法创建出我们的增强器,然后spring根据我们AOP的使用类型帮我们创建出JDK
或者Cglib的动态代理对象
4.执行代理方法
我们将Advisor封装为MethodInterceptors方法拦截链,逆序执行AOP的增强方法,通过责任链的设计模式完成我们的增强处理。
本文地址:https://blog.csdn.net/shangshanzixu/article/details/112883171