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的增强方法,通过责任链的设计模式完成我们的增强处理。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值