基于 Spring Framework v5.2.6.RELEASE
概述
前面两篇文章分析了在注解配置和 XML 配置的情况下,Spring 是如何开启 AOP 特性的,经过源码分析我们知道,这两种方式的 AOP 开启,本质上都是注册了一个用来创建 AOP 代理的后处理器。
对于在 XML 中配置切面的情况,Spring 会把创建代理的工作交给 AspectJAwareAdvisorAutoProxyCreator 后处理器来处理,而对于通过注解配置切面的情况,则交由 AnnotationAwareAspectJAutoProxyCreator 后处理器处理。
在本文章,将对这两个后处理器进行分析,了解他们大致的工作原理。
继承关系
AspectJAwareAdvisorAutoProxyCreator 和 AnnotationAwareAspectJAutoProxyCreator 两个后处理器的继承关系,在前两篇文章中已经了解过了,这里我们再做简单的回顾。
从上图中可以知道,这两个类是直接继承的父子类,他们有很多共同继承的类和实现的接口,可以推测出他们的工作逻辑有很大一部分是相同的。
由于他们是作为后处理器注册到 Spring 容器中的,因此,他们完成 AOP 代理创建的逻辑,一定是在后处理器的方法中。从上图中看到,他们共实现了三个后处理器的接口,接下来,我们再看这三个接口中定义的方法。
实现接口
先看看这三个接口都定义了哪些方法。
既然后处理器的作用要生成一个代理对象,那么,我们就应该去分析后处理器中可以修改被处理的 Bean 对象的处理方法,再上图中罗列的方法中有以下这些:
postProcessBeforeInstantiation
方法可以在 Spring 实例化 Bean 对象之前,创建一个 Bean 对象。postProcessBeforeInitialization
方法可以在 Bean 的初始化方法被执行前,修改 Bean 对象。postProcessAfterInitialization
方法可以在 Bean 的初始化方法被执行前,修改 Bean 对象。
以上三个方法,都可能在执行的过程中,将当前的 Bean 对象,修改为新创建的代理对象。因此,接下来,我们需要从两个后处理器中找到这三个方法的实现逻辑。
不过,在源码中可以发现,这两个后处理器的后处理方法,都是在它们共同的父类 AbstractAutoProxyCreator 中实现的,所以,我们之后只需要分析 AbstractAutoProxyCreator 类中实现的处理方法就行了。并且,postProcessBeforeInitialization
方法的实现是一个没有任何处理逻辑的默认实现,我们接下来从postProcessBeforeInstantiation
和postProcessAfterInitialization
两个方法中分析自动创建代理的逻辑。
代理创建的原理
下面从 AbstractAutoProxyCreator 的源码中,找到这两个方法进行分析。
postProcessBeforeInstantiation
先看postProcessBeforeInstantiation
方法
publicObjectpostProcessBeforeInstantiation(Class<?>beanClass, StringbeanName) { ObjectcacheKey=getCacheKey(beanClass, beanName); if (!StringUtils.hasLength(beanName) ||!this.targetSourcedBeans.contains(beanName)) { if (this.advisedBeans.containsKey(cacheKey)) { returnnull; } if (isInfrastructureClass(beanClass) ||shouldSkip(beanClass, beanName)) { this.advisedBeans.put(cacheKey, Boolean.FALSE); returnnull; } } // Create proxy here if we have a custom TargetSource.// Suppresses unnecessary default instantiation of the target bean:// The TargetSource will handle target instances in a custom fashion.TargetSourcetargetSource=getCustomTargetSource(beanClass, beanName); if (targetSource!=null) { if (StringUtils.hasLength(beanName)) { this.targetSourcedBeans.add(beanName); } Object[] specificInterceptors=getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource); Objectproxy=createProxy(beanClass, beanName, specificInterceptors, targetSource); this.proxyTypes.put(cacheKey, proxy.getClass()); returnproxy; } returnnull; }
方法的核心是后半部分的if
语句块,在if语句块之前,通过getCustomTargetSource
获取了当前 Bean 对象的自定义 TargetSource。TargetSource 指的是,Spring 创建的代理在调用目标方法时候要查找的目标来源,在创建代理对象时,当前的 Bean 对象,会被封装成一个 TargetSource 交给代理类,用于找到被增强的对象本身。
通常情况下,我们不会自定义 TargetSource,因此,这个方法并不是我们要找的创建代理的地方。
postProcessAfterInitialization
接下来,找到postProcessAfterInitialization
方法。
publicObjectpostProcessAfterInitialization(Objectbean, StringbeanName) { if (bean!=null) { ObjectcacheKey=getCacheKey(bean.getClass(), beanName); if (this.earlyProxyReferences.remove(cacheKey) !=bean) { returnwrapIfNecessary(bean, beanName, cacheKey); } } returnbean; }
这个方法是在 Bean 实例被执行初始化操作后被调用的,因此方法可以通过参数拿到 Bean 实例对象本身,以及 Bean 的名称。
首先,确保了 Bean 不为空之后,通过getCacheKey
方法获得了一个缓存 Key。这个方法在刚刚的postProcessBeforeInstantiation
方法中也见过,我们来看一下这个方法。
protectedObjectgetCacheKey(Class<?>beanClass, StringbeanName) { if (StringUtils.hasLength(beanName)) { return (FactoryBean.class.isAssignableFrom(beanClass) ?BeanFactory.FACTORY_BEAN_PREFIX+beanName : beanName); } else { returnbeanClass; } }
方法中判断了 Bean 的名称是否为空,如果不为空,则根据当前的 Bean 是不是一个 FactoryBean 来返回带或者不带工厂前缀的 Bean 名称,如果 Bean 的名称为空,则直接返回 Bean 得类型本身。
这个方法的目的是获得一个缓存 Key,用于 AbstractAutoProxyCreator 中的缓存容器。
回到postProcessAfterInitialization
方法中,接着,从earlyProxyReferences
集合中,移除当前 Bean 对象对应的缓存 Key 保存的内容。那这个集合中存放了什么呢?在 AbstractAutoProxyCreator 源码中,除了这里,只有一处操作了earlyProxyReferences
集合,而且是put
操作,在另外一个方法中。
publicObjectgetEarlyBeanReference(Objectbean, StringbeanName) { ObjectcacheKey=getCacheKey(bean.getClass(), beanName); this.earlyProxyReferences.put(cacheKey, bean); returnwrapIfNecessary(bean, beanName, cacheKey); }
这其实也是一个后处理器方法,之所以在寻找创建代理逻辑的时候没有考虑这个方法,是因为这个方法是在获取早期 Bean 对象的时候被调用的,也就是说,它不一定会被调用,而且调用的时机也不确定。在方法中,通过缓存 Key 向earlyProxyReferences
集合中存放了早期的代理引用,方法最后返回了调用wrapIfNecessary
方法的结果,这个方法我们稍后介绍。
再次回到postProcessBeforeInstantiation
中,如果从earlyProxyReferences移除的内容,并不是 Bean 本身,则执行wrapIfNecessary
方法并将结果作为后处理方法的结果返回。
wrapIfNecessary 方法
到这里,我们就需要看wrapIfNecessary方法,从名字就可以看出,它的作用是在必要的时候,对 Bean 对象进行包装,并且包装好的结果会作为容器中 Bean 的对象。因此,这个方法就是用来创建 Bean 对象代理的方法。
// 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 对象本身。
这部分逻辑,放到之后的文章来分析。
总结
本文分析了用于创建 AOP 代理对象的后处理器,主要是 AbstractAutoProxyCreator 类中的后处理方法。从它实现的后处理器接口中定义的方法中,找到了用于创建 AOP 代理的逻辑是在postProcessBeforeInstantiation方法中,也就是 AOP 代理是 Bean 执行完初始化逻辑之后创建的。
下一篇开始,将深入wrapIfNecessary
方法,分析代理对象创建的过程。