基于 Spring Framework v5.2.6.RELEASE
概述
上一篇中,我们从 AspectJAwareAdvisorAutoProxyCreator 和 AnnotationAwareAspectJAutoProxyCreator 共同的父类 AbstractAutoProxyCreator 中,找到了 Spring 创建代理的逻辑。在postProcessAfterInitialization
方法中,Spring 为已经完成初始化的 Bean 实例创建代理,其中,最核心的就是调用了wrapIfNecessary
方法。
本文将从wrapIfNecessary方法入手,分析 AOP 代理创建的过程。
wrapIfNecessary 方法
先看wrapIfNecessary方法的源码。
// org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#wrapIfNecessaryprotectedObjectwrapIfNecessary(Objectbean, StringbeanName, ObjectcacheKey) { if (StringUtils.hasLength(beanName) &&this.targetSourcedBeans.contains(beanName)) { returnbean; } if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) { returnbean; } if (isInfrastructureClass(bean.getClass()) ||shouldSkip(bean.getClass(), beanName)) { this.advisedBeans.put(cacheKey, Boolean.FALSE); returnbean; } // Create proxy if we have advice.Object[] specificInterceptors=getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null); if (specificInterceptors!=DO_NOT_PROXY) { this.advisedBeans.put(cacheKey, Boolean.TRUE); Objectproxy=createProxy( bean.getClass(), beanName, specificInterceptors, newSingletonTargetSource(bean)); this.proxyTypes.put(cacheKey, proxy.getClass()); returnproxy; } this.advisedBeans.put(cacheKey, Boolean.FALSE); returnbean; }
这个方法的源码大致可以分为两部分。前半部分是一些判断,主要过滤了一些不需要进行代理的情况,并直接将 Bean 实例返回;后半部分是主要处理逻辑的部分。
我们先看前半部分,这里判断了三种不需要处理的情况。
- 如果这个 Bean 对象配置了自定义的 TargetSource,且已经被
postProcessBeforeInstantiation
方法处理过滤, 则此处不需要处理。 - 如果
advisedBeans
集合中,这个对象的cacheKey
对应的值是false
,则说明这个对象不需要被处理。 - 如果当前对象的类型是基础类,包括用来配置 AOP 的类型,那么不需要被处理,并且在
advisedBeans
集合中,将它的cacheKey
对应的值配置为false
,这样下次直接在集合中判断其是否需要处理就可以了。
接下来就是主要的业务逻辑了,也就是下面这部分。
// Create proxy if we have advice.Object[] specificInterceptors=getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null); if (specificInterceptors!=DO_NOT_PROXY) { this.advisedBeans.put(cacheKey, Boolean.TRUE); Objectproxy=createProxy( bean.getClass(), beanName, specificInterceptors, newSingletonTargetSource(bean)); this.proxyTypes.put(cacheKey, proxy.getClass()); returnproxy; } this.advisedBeans.put(cacheKey, Boolean.FALSE); returnbean;
先从整体来看,首先,会调用getAdvicesAndAdvisorsForBean
方法,获取到一个名叫specificInterceptors
的 Object 数组,从方法名称中可以看出,这里是为了获取当前 Bean 对象能够匹配到的增强的集合。
如果获取到的集合为空,那么说明当前的对象不需要增强,也就不需要创建代理,直接返回即可。再返回之前,还会在advisedBeans集合中,将其对应的值设置为false,这样,下次就可以直接判断这个 Bean 对象不处理即可。
如果获取到的集合不为空,那么,就通过createProxy
方法为其创建代理,然后在添加一些相应的缓存信息,最后将代理对象返回,这样,最终注册到 Spring 容器中的 Bean 对象就是这个代理对象。
虽然这个方法中没有包含多少细节,但是,我们可以从中看出,Spring 创建 AOP 代理大致可以分为两个步骤,第一步是根据 Bean 对象找到与之匹配的增强,第二步是为其创建代理对象。
接下来,我们在进入这两个关键的方法,看一下其中的主要逻辑。
getAdvicesAndAdvisorsForBean
先看getAdvicesAndAdvisorsForBean
方法,这个方法的实现可以在 AbstractAdvisorAutoProxyCreator 中找到
// org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#getAdvicesAndAdvisorsForBeanprotectedObject[] getAdvicesAndAdvisorsForBean( Class<?>beanClass, StringbeanName, TargetSourcetargetSource) { List<Advisor>advisors=findEligibleAdvisors(beanClass, beanName); if (advisors.isEmpty()) { returnDO_NOT_PROXY; } returnadvisors.toArray(); }
其主要逻辑是调用了findEligibleAdvisors
方法,并将返回的列表转换为数组。我们进入findEligibleAdvisors
方法。
// org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#findEligibleAdvisorsprotectedList<Advisor>findEligibleAdvisors(Class<?>beanClass, StringbeanName) { List<Advisor>candidateAdvisors=findCandidateAdvisors(); List<Advisor>eligibleAdvisors=findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName); extendAdvisors(eligibleAdvisors); if (!eligibleAdvisors.isEmpty()) { eligibleAdvisors=sortAdvisors(eligibleAdvisors); } returneligibleAdvisors; }
我们这里先做宏观的流程梳理,暂时不深入细节,因此,这里根据源码中的注释信息,结合方法和变量的名称,大致分析方法的逻辑。
首先,通过findCandidateAdvisors
方法找到候选的增强信息,这里应该是找到所有我们通过注解和 XML 配置的切面信息中的增强。
然后,再通过findAdvisorsThatCanApply
方法,筛选出「有资格的」(eligible)增强信息,这里应该指的是能够与当前的 Bean 对象匹配的增强。
第三行中调用的extendAdvisors方法,是对获取到的增强列表的一个扩展处理。
最后返回排序后的结果。
createProxy
再大概看一下createProxy
方法的源码。
protectedObjectcreateProxy(Class<?>beanClass, StringbeanName, Object[] specificInterceptors, TargetSourcetargetSource) { if (this.beanFactoryinstanceofConfigurableListableBeanFactory) { AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass); } ProxyFactoryproxyFactory=newProxyFactory(); proxyFactory.copyFrom(this); if (!proxyFactory.isProxyTargetClass()) { if (shouldProxyTargetClass(beanClass, beanName)) { proxyFactory.setProxyTargetClass(true); } else { evaluateProxyInterfaces(beanClass, proxyFactory); } } Advisor[] advisors=buildAdvisors(beanName, specificInterceptors); proxyFactory.addAdvisors(advisors); proxyFactory.setTargetSource(targetSource); customizeProxyFactory(proxyFactory); proxyFactory.setFrozen(this.freezeProxy); if (advisorsPreFiltered()) { proxyFactory.setPreFiltered(true); } returnproxyFactory.getProxy(getProxyClassLoader()); }
这里可以看到一个关键的 ProxyFactory 类,以上整个方法中都围绕它展开。首先创建了一个 ProxyFactory 对象,然后对其进行各种各样的配置,最后通过它的getProxy
方法创建代理对象。
具体的细节,我们放到之后再深入分析。
题外话:关于切面配置的加载
除了以上的流程,这里还有一个地方需要额外关注一下,那就是在查找切面集合的步骤中,上面提到了一个findCandidateAdvisors
方法。
在 Spring 中配置切面有两种方式,分别是 XML 配置和注解配置,虽然切面的工作原理都是一样的,但是获取切面配置的逻辑有所不同。
因此,findCandidateAdvisors
方法在 AspectJAwareAdvisorAutoProxyCreator 和 AnnotationAwareAspectJAutoProxyCreator 这两个后处理器的实现类中有不同的实现。AspectJAwareAdvisorAutoProxyCreator 继承了父类中的实现,而 AnnotationAwareAspectJAutoProxyCreator 重写了父类的实现。
对于 XML 配置的切面,需要从 XML 配置中加载切面的配置,而 XML 配置是在 Spring 容器初始化的时候进行的。对于注解配置的切面,则需要加载完用来配置切面的 Bean 对象后读取。因此,对于findCandidateAdvisors
方法的原理分析,之后会分两种情况来分析。
总结
本文分析了 Spring 创建 AOP 代理的重要方法wrapIfNecessary
以及它为 Bean 对象创建代理对象的主要流程。从下一篇开始,我将围绕这个流程,做深入的原理分析。