上一篇文章我們從XML 配置文件的方式剖析了AOP的源碼,我們也說了,雖然現在用XML配置的幾乎沒有了,但作為學習的例子,XML配置仍然是我們理解Spring AOP 的一個絕好的樣本,但作為一個由追求的程序員,我們天天使用的注解方式的AOP 肯定也是要去看看到底是如何實現的。現在有了之前閱讀 XML 配置的源碼的基礎,今天我們來閱讀注解方式的源碼也變得輕松起來。
還記得我們之前說過,XML 配置的AOP是使用 ProxyFactoryBean ,實現了 FactoryBean的接口,而FactoryBean是Spring特意留給開發者們擴展的接口,而Spring 留給開發者們不止一個擴展接口,比如 BeanPostProcess 接口,實現著接口就可以在每個Bean的生成前后做一些增強或自定義(具體Spring 留給我們有哪些擴展接口,樓主有機會將會再寫一篇文章解析)。
接下來就要好好講講我們上篇文章漏講的接口設計。這是我們理解 AOP 的基礎。
先從 ProxyFactoryBean 講起,這個熟悉的哥們。
1. ProxyFactoryBean 類結構
1.1 ProxyCreatorSupport 類結構圖
它繼承了 ProxyCreatorSupport 這個類,這個類很重要,我們看看該類結構
該類有2個重要的方法,分別是獲取代理工廠,創建代理。那么代理工廠是什么呢?AopProxyFactory ,是個接口,只定義了一個方法:AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException, 并且該接口目前只有一個默認實現類:DefaultAopProxyFactory,該類主要重寫了接口方法 createAopProxy, 內部邏輯是根據給定的類配置來創建不同的代理 AopProxy,那么 AopProxy 是什么呢?就是真正創建代理的工廠,他是一個接口,有3個實現:
1.2 AopProxy 接口
1.3 AopProxy 繼承結構
從名字上可以看出來,一個是 JDK 動態代理,一個是 Cglib 代理,ObjenesisCglibAopProxy 擴展了它的父類 CglibAopProxy,在 DefaultAopProxyFactory 的實現里,使用的就是 ObjenesisCglibAopProxy 來實現 Cglib 的代理。他們分別實現了自己的getProxy 方法用以創建代理。我們看看這兩個類的繼承結構:
1.4 JdkDynamicAopProxy 繼承結構
1.5 CglibAopProxy 繼承結構沒什么,主要是眾多內部類
可以看到喲非常多的內部類,這些內部類是為了實現了 Cglib 的各種回調而實現的。主要實現了 MethodInterceptor 接口,
Callback 接口,Joinpoint 接口,Invocation 接口等待,總之是實現了Spring 的 cglib 模塊的各種接口。
說了那么多,我們回來看看 ProxyCreatorSupport ,下面是 ProxyCreatorSupport 的繼承結構
2. ProxyCreatorSupport 類繼承圖
該類有3個子類, 其中就有一個我們熟悉的 ProxyFactoryBean,該類實現了我們熟悉的 FactoryBean,還有一個可以獲取容器內Bean的 BeanFactoyAware 接口,第二個是陌生的 AspectJProxyFactory 類,該類是用于集成 Spring 和 AspectJ 的。而最后一個類ProxyFactory 就是我們今天的主角,Spring 的類注釋說:用于編程使用的AOP代理,而不是在bean工廠中通過聲明式設置。這個類提供了一種簡單的方法,可以在定制的用戶代碼中獲取和配置AOP代理實例
,大概意思就是通過編程的方式獲取Bean 代理吧,而不是通過配置文件的方式。我們今天就可以見識到。
3. AnnotationAwareAspectJAutoProxyCreator 類
這個類的名字很長,為什么要說這個類呢?還記得我們剛開始說的 BeanPostProcessor 擴展接口嗎?我們說該接口是spring 留給開發人員自定義增強bean的接口。而該類則實現了該接口,看名字也知道,該類是根據注解自動創建代理的創建者類。我們看看他的類圖:
可以看到,最底層的該類實現了 BeanPostProcessor 接口,可以在每個bena生成前后做操作。該類由 Rod Johnson 編寫,注釋上是這么說的:任何AspectJ注釋的類都將自動被識別,它們也會被識別
。和我們預想的一致。
我們知道了 AnnotationAwareAspectJAutoProxyCreator 是根據注解自動創建代理,而該類也算是 ProxyBean 的代理,那么,和它一樣繼承抽象父類的其他幾個類的作用是什么呢?來都來了,就看看吧!我們看看類圖:
可以看到該類由4個實現:他們實現了不同的創建代理的方式:
- 匹配Bean的名稱自動創建匹配到的Bean的代理,實現類BeanNameAutoProxyCreator
- 根據Bean中的AspectJ注解自動創建代理,實現類AnnotationAwareAspectJAutoProxyCreator,也就是我們今天說的注解類。
- 根據Advisor的匹配機制自動創建代理,會對容器中所有的Advisor進行掃描,自動將這些切面應用到匹配的Bean中,實現類DefaultAdvisorAutoProxyCreator
- InfrastructureAdvisorAutoProxyCreator,該類只在 AopConfigUtils 中的靜態塊用到,該類的注釋:自動代理創建者只考慮基礎設施顧問bean,忽略任何應用程序定義的顧問。意思應該是只是Sprnig的基礎代理,開發者的應用會忽略。有知道的同學可以告訴我。
加上我們的ProxyFactoryBean,一共5種實現方法。從這里可以看出Spring 對于擴展的軟件設計是多么優秀。
那么我們就來看看 AnnotationAwareAspectJAutoProxyCreator 是如何創建代理的。我們說 BeanPostProcessor 是Spring 留給我們擴展的接口,那么他是如何定義的呢?我們看看該接口:
public interface BeanPostProcessor {
Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}
該接口定義了兩個方法,一個是在bean初始化之前執行,一個是在bean初始化之后執行。也就是說,開發者可以在這兩個方法中做一些有趣的事情。我們看看 AnnotationAwareAspectJAutoProxyCreator 是如何實現該方法的。實際上 AnnotationAwareAspectJAutoProxyCreator 的抽象父類已經實現了該方法,我們看看是如何實現的:
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
return bean;
}
/**
* Create a proxy with the configured interceptors if the bean is
* identified as one to proxy by the subclass.
* @see #getAdvicesAndAdvisorsForBean
*/
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (!this.earlyProxyReferences.contains(cacheKey)) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
before 方法直接返回了bean,并沒有做什么增強操作,重點在after方法,我們可以看該方法的注釋:如果bean是由子類標識的,那么就創建一個配置的攔截器的代理。Spring 就是在這里創建了代理,我們進入關鍵方法 wrapIfNecessary 看看。該方法用來包裝給定的Bean。
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
if (beanName != null && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
// Create proxy if we have advice.
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
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;
}
我們已將可以看到一個關鍵一行代碼:Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean)),創建一個代理,該方法攜帶了bean的Class對象,benaName, 通知器數組,還有一個包裝過的單例Bean,我們看看該方法實現(該方法對于我們來說已經到終點了),
protected Object createProxy(
Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {
if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
}
ProxyFactory proxyFactory = new ProxyFactory();
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);
}
return proxyFactory.getProxy(getProxyClassLoader());
}
我們能夠看到其中有一行讓我們激動的代碼,就是 ProxyFactory proxyFactory = new ProxyFactory(),創建了一個ProxyFactory 對象,我們剛剛說過,該對象和ProxyFactoryBean一樣,繼承了 ProxyCreatorSupport, 因此也就和 ProxyFactoryBean 一樣擁有了 getProxy 方法,到這里,我們的一切都豁然開朗。當然上面幾行代碼是設置了通知器鏈。我們先按下不表。
ProxyFactoryBean 擴展了 FactoryBean 接口, AnnotationAwareAspectJAutoProxyCreator 擴展了 BenaPostProcessor 了接口,其目的都是在Bean生成的時候做增強操作,Spring 通過這兩種方式,完成了兩種不同的代理生成方式,但最終都是繼承了 ProxyCreatorSupport 類,該類才是生成代理的核心類。
我們可以看看XML 配置方式和 注解方式的方法堆棧調用圖,從中我們可以看出一些端倪:
XML 配置方式堆棧圖
注解配置方法堆棧圖
我們可以看到兩者在AbstractBeanFactory 的 doGetBean 方法開始分道揚鑣,走向了不同的邏輯,那么我們看看到底哪里不同,直接看代碼:我們看XML配置堆棧,在258行:
從這里進入,該方法做了些什么呢?為什么讓他們走向不同的路線?我們看看該方法:
該方法有個重要的判斷:是否是 FactoryBean 的子類型,很明顯,我們的XML配置的ProxyFacoroyBean 返回 false,而注解方式的Bean則返回 false,ProxyFacoroyBean 會一直向下走,直到創建代理,而注解方式則會直接返回。走到302行:
注解方式會執行 getSingleton 方法,最后觸發 createBean 回調方法,完成創建代理的過程。
到此為止,現在我們知道了到 XML 配置方式的 AOP 和注解的方式AOP 的生成區別。我們可以開始總結了。
4. 總結
首先,通過分析源碼我們知道注解方式和 XML 配置方式的底層實現都是一樣的,都是通過繼承 ProxyCreatorSupport 來實現的,不同的通過擴展不同的 Spring 提供的接口,XML 擴展的是FactoryBean 接口, 而注解方式擴展的是 BenaPostProcessor 接口,通過Spring 的擴展接口,能夠對特定的Bean進行增強。而 AOP 正式通過這種方式實現的。這也提醒了我們,我們也可以通過擴展 Spring 的某些接口來增強我們需要的 Bean 的某些功能。當然,篇幅有限,我們這篇文章只是了解了XML 配置方式和注解方式創建代理的區別,關于如何 @Aspect 和 @Around 的底層實現,還有通知器的底層實現,我們還沒有分析,但我們隱隱的感覺到,其實萬變不離其宗,底層的也是通過擴展 advice 和 pointcut 接口來實現的。 我們將會在后面的文章繼續分析 AOP 是如何編織通知的。
good luck !!??!