前言
最近看了《從零開(kāi)始寫(xiě)JavaWeb框架》,想比較一下Spring AOP的實(shí)現(xiàn)方式和書(shū)的上實(shí)現(xiàn)方式有什么不同,所以先把Spring AOP的源碼讀一下,再進(jìn)行比較。
Spring的源碼實(shí)在是復(fù)雜,在讀的過(guò)程中參考了很多書(shū)和網(wǎng)上的文章,本文算是這些文章的總結(jié),再加上一些我自己對(duì)另個(gè)細(xì)節(jié)的理解。
本文分成 3 部分:
- 程序入口
- 切面和增強(qiáng)的取得
- 代理的生成
一,注冊(cè)AspectJAnnotationAutoProxyCreator
如果使用<aop:aspectj-autoproxy />標(biāo)簽來(lái)自動(dòng)生成代理的話(huà),入口程序是AopNamespaceHandler。在AopNamespaceHandler中,下面一段代碼是對(duì)<aop:aspectj-autoproxy />標(biāo)簽執(zhí)行的調(diào)用:
registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
AspectJAutoProxyBeanDefinitionParser解析器中,首先調(diào)用的parse方法。parse方法中有一行代碼:
AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);
我們看一下registerAspectJAnnotationAutoProxyCreatorIfNecessary方法的實(shí)際內(nèi)容:
public static void registerAutoProxyCreatorIfNecessary(
ParserContext parserContext, Element sourceElement) {
// 注冊(cè)或更新 AutoProxyCreator 定義 beanName 為 org.Springframework.aop.config.internalAutoProxyCreator的BeanDefinition
// 如果internalAutoProxyCreator的BeanDefinition已經(jīng)存在,而根據(jù)優(yōu)先級(jí)更新BeanDefinition
// 在這里我們注冊(cè)的是AnnotationAwareAspectJAutoProxyCreator
BeanDefinition beanDefinition = AopConfigUtils.registerAutoProxyCreatorIfNecessary(
parserContext.getRegistry(), parserContext.extractSource(sourceElement));
// 對(duì)于 proxy-target-class 以及 expose-proxy 屬性的處理
useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
// 注冊(cè)組件并通知,便于監(jiān)聽(tīng)器作進(jìn)一步處理
// 其中 beanDefinition 的 className 為 AnnotationAwareAspectJAutoProxyCreator
registerComponentIfNecessary(beanDefinition, parserContext);
}
那為什么注冊(cè)AnnotationAwareAspectJAutoProxyCreator,注冊(cè)AnnotationAwareAspectJAutoProxyCreator有什么用呢?
其實(shí),實(shí)現(xiàn)AOP處理是其實(shí)是通過(guò)BeanPostProcessor機(jī)制實(shí)現(xiàn)的。AnnotationAwareAspectJAutoProxyCreator的父類(lèi)也實(shí)現(xiàn)一個(gè)BeanPostProcessor類(lèi)型的接口,而生成代理的邏輯就在AnnotationAwareAspectJAutoProxyCreator的BeanPostProcessor接口實(shí)現(xiàn)里面。
更嚴(yán)謹(jǐn)?shù)卣f(shuō),AnnotationAwareAspectJAutoProxyCreator的父類(lèi)實(shí)現(xiàn)的接口是
SmartInstantiationAwareBeanPostProcessor,主要是Spring框架內(nèi)部使用的一個(gè)接口。而這個(gè)接口的父接口InstantiationAwareBeanPostProcessor 是實(shí)現(xiàn)代理的重點(diǎn)之一。
這3個(gè)接口的關(guān)系如下:
SmartInstantiationAwareBeanPostProcessor -> InstantiationAwareBeanPostProcessor -> BeanPostProcessor
為什么說(shuō)是是InstantiationAwareBeanPostProcessor接口的子接口,接口是重點(diǎn)之一?那InstantiationAwareBeanPostProcessor接口是什么接口呢?
BeanPostProcessor主要作用于Bean實(shí)例化后,初始化前后。InstantiationAwareBeanPostProcessor雖然是BeanPostProcessor的子接口,但它的調(diào)用時(shí)間點(diǎn)其發(fā)生在Bean實(shí)例化前,在真正調(diào)用doCreate()創(chuàng)建bean實(shí)例之前。
在創(chuàng)建Bean實(shí)例之前,會(huì)先調(diào)用resolveBeforeInstantiation方法,這個(gè)方法是生成Bean代理的地方。如果此方法返回值不為空則直接返回生成的Bean的代理,如果為空就向下走正常的Bean生成流程。
spring注釋“Give BeanPostProcessors a chance to return a proxy instead of the target bean instance. ”給BeanPostProcessors一個(gè)機(jī)會(huì)返回代理proxy對(duì)象。
而InstantiationAwareBeanPostProcessor接口方法,就是在resolveBeforeInstantiation方法中調(diào)用的。所以可以看出,BeanPostProcessore有很多,但Spring AOP的實(shí)現(xiàn)就是通過(guò)InstantiationAwareBeanPostProcessor這個(gè)BeanPostProcessor實(shí)現(xiàn)的??匆幌略创a:
protected Object createBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
throws BeanCreationException {
......
try {
// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
// 如果返回值不為空,說(shuō)明生成成了此BeanName的代理,直接返回代理對(duì)象
Object bean = resolveBeforeInstantiation(beanName, mbd);
if (bean != null) {
return bean;
}
}
catch (Throwable ex) {
......
}
// 如果沒(méi)有生成代理對(duì)象,就按正常流程走,生成Bean對(duì)象
Object beanInstance = doCreateBean(beanName, mbd, args);
.....
return beanInstance;
}
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
Object bean = null;
if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
// Make sure bean class is actually resolved at this point.
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
Class<?> targetType = determineTargetType(beanName, mbd);
if (targetType != null) {
// 調(diào)用InstantiationAwareBeanPostProcessor接口的地方
bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
if (bean != null) {
bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
}
}
}
mbd.beforeInstantiationResolved = (bean != null);
}
return bean;
}
protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass, String beanName)
throws BeansException {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
// 轉(zhuǎn)換成InstantiationAwareBeanPostProcessor接口,并調(diào)用
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
Object result = ibp.postProcessBeforeInstantiation(beanClass, beanName);
if (result != null) {
return result;
}
}
}
return null;
}
順帶說(shuō)一下,注冊(cè)AnnotationAwareAspectJAutoProxyCreator的目的是:把這個(gè)類(lèi)的BeanDefinition通過(guò)registerBeanDefinition方法(DefaultListableBeanFactory類(lèi)中)加入到beanDefinitionMap中,作為一個(gè)Bean讓Spring管理,這樣Spring就可以隨意取得它了。
如果使用<aop:aspectj-autoproxy />標(biāo)簽來(lái)自動(dòng)生成代理的話(huà),入口程序是AopNamespaceHandler。那AopNamespaceHandler 是在什么地方被調(diào)用的呢?
這個(gè)問(wèn)題讓我們從容器啟動(dòng)的地方開(kāi)始說(shuō)明。以FileSystemXmlApplicationContext 為例,這個(gè)類(lèi)的入口是構(gòu)造函數(shù)里面的refresh() 方法。從refresh() 方法開(kāi)始,調(diào)用流程是這樣的:(以下流程全部是嵌套調(diào)用的關(guān)系)
1. refresh() ->
刷新容器
2. obtainFreshBeanFactory() ->
獲得刷新后的Bean容器
3. refreshBeanFactory() ->
刷新Bean容器
4. loadBeanDefinitions() ->
加載BeanDefinition
5. XmlBeanDefinitionReader#loadBeanDefinitions
新建一個(gè)XmlBeanDefinitionReader實(shí)例(new XmlBeanDefinitionReader(beanFactory)),調(diào)用這個(gè)實(shí)例的loadBeanDefinitions方法。
6. XmlBeanDefinitionReader#doLoadBeanDefinitions
7. XmlBeanDefinitionReader#registerBeanDefinitions
8. XmlBeanDefinitionReader#createBeanDefinitionDocumentReader
在這個(gè)方法中取得了DefaultBeanDefinitionDocumentReader實(shí)例。接下來(lái)調(diào)用這個(gè)實(shí)例的方法。
9. DefaultBeanDefinitionDocumentReader#registerBeanDefinitions
在這個(gè)方法中,根據(jù)URI判斷是否使用AopNamespaceHandler
10. DefaultBeanDefinitionDocumentReader#parseBeanDefinitions
從registerBeanDefinitions方法開(kāi)始,內(nèi)部連續(xù)調(diào)用一系列方法,一直調(diào)用到parseBeanDefinitions方法。在這個(gè)方法中,根據(jù)XML文件的URI判斷使用哪些解析器,例如是<Beans>類(lèi)標(biāo)簽解析器,還是<aop>類(lèi)標(biāo)簽解析器。
如果是需要<aop>標(biāo)簽解析器的話(huà),在this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri)代碼中,從配置文件(spring.handlers)從取出AopNamespaceHandler的類(lèi)名,生成這個(gè)類(lèi)的實(shí)例,然后調(diào)用這個(gè)類(lèi)的parse方法。
11. AopNamespaceHandler#parse
這個(gè)方法的功能是,根據(jù)具體標(biāo)簽調(diào)用具體解析器的parse方法。
- <aop:aspectj-autoproxy>:AspectJAutoProxyBeanDefinitionParser
- <aop:config>:ConfigBeanDefinitionParser
等。
這個(gè)方法的調(diào)用,又回到了我們最初講的AopNamespaceHandler入口的地方。
到此為止,從容器到AopNamespaceHandler類(lèi)調(diào)用的過(guò)程也講完了。
二,AspectJAnnotationAutoProxyCreator的流程
通過(guò)上面的內(nèi)容,我們知道了注冊(cè)AnnotationAwareAspectJAutoProxyCreator的意義,并且知道了生成代理是在它的BeanPostProcessor接口里做的,現(xiàn)在看看被實(shí)現(xiàn)的接口的內(nèi)容。(postProcessAfterInitialization 具體實(shí)現(xiàn)是在其父類(lèi) AbstractAutoProxyCreator 中完成的):
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean != null) {
// 根據(jù)給定的 bean 的 class 和 name 構(gòu)建出個(gè) key,格式:beanClassName_beanName
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (!this.earlyProxyReferences.contains(cacheKey)) {
// 如果它適合被代理,則需要封裝指定 bean。
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
// 是否已經(jīng)處理過(guò)
if (beanName != null && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
// 無(wú)需增強(qiáng)
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
// 給定的 bean 類(lèi)是否代表一個(gè)基礎(chǔ)設(shè)施類(lèi),基礎(chǔ)設(shè)施類(lèi)不應(yīng)代理,或者配置了指定 bean 不需要自動(dòng)代理
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// 如果存在增強(qiáng)方法則創(chuàng)建代理(*重要*)
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
// 如果獲取到了增強(qiáng)則需要針對(duì)增強(qiáng)創(chuàng)建代理
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
// 創(chuàng)建代理(*重要*)
Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
這里有兩個(gè)方法特別重要:
- getAdvicesAndAdvisorsForBean:如果Bean是要被代理的對(duì)象的話(huà),取得Bean相關(guān)的Interceptor
- createProxy:創(chuàng)建代理
下一篇文章,我們就這兩個(gè)方法的下面的流程分開(kāi)來(lái)分析一下,首先分析getAdvicesAndAdvisorsForBean相關(guān)代碼。
關(guān)于接口實(shí)現(xiàn)的補(bǔ)充:
AnnotationAwareAspectJAutoProxyCreator 一共實(shí)現(xiàn)了2個(gè)BeanPostProcessor 的接口,的4個(gè)方法:
- postProcessBeforeInstantiation(InstantiationAwareBeanPostProcessor)
- postProcessAfterInstantiation(InstantiationAwareBeanPostProcessor)
- postProcessBeforeInitialization(BeanPostProcessor)
- postProcessAfterInitialization(BeanPostProcessor)
postProcessBeforeInstantiation(InstantiationAwareBeanPostProcessor接口)方法中,這個(gè)方法是在AnnotationAwareAspectJAutoProxyCreator的基類(lèi)AbstractAutoProxyCreator中實(shí)現(xiàn)的。細(xì)看一下,在postProcessAfterInitialization方法中也有類(lèi)似的生成代理的代碼。這是為什么呢?
上網(wǎng)找了一些資料,在postProcessBeforeInstantiation方法中有一個(gè)判斷:
如果某個(gè)
Bean設(shè)置了自定義TargetSource的話(huà),就在本方法中進(jìn)行生成代理而
postProcessAfterInitialization則沒(méi)有這樣的判斷,只是在生成代理前判斷了一下代理是否已經(jīng)生成。具體為什么有這樣的必須還不清楚(以后有需要調(diào)查一下),但結(jié)果就是:
- 如果
Bean設(shè)置了自定義TargetSource,就在postProcessBeforeInstantiation中生成代理 - 如果沒(méi)有,就在
postProcessAfterInitialization中生成代理。
最后,不管理在哪個(gè)方法里生成代理,在創(chuàng)建每個(gè)Bean時(shí)都會(huì)被調(diào)用這兩個(gè)方法,代理的生成邏輯就是在這兩個(gè)方法中實(shí)現(xiàn)的。
關(guān)于TargetSource:spring-aop組件詳解——TargetSource目標(biāo)源
關(guān)于自定義TargetSource:《Spring揭密》的9.6章節(jié)