Spring源碼分析:實(shí)現(xiàn)AOP(轉(zhuǎn)載)
Posted on 2007-04-24 09:37 dennis 閱讀(7545) 評(píng)論(0) 編輯 收藏 所屬分類: java 、源碼解讀 這兩天一直在讀spring1.2的AOP實(shí)現(xiàn)源碼,AOP實(shí)現(xiàn)原理說起來很簡(jiǎn)單,對(duì)于實(shí)現(xiàn)業(yè)務(wù)接口的對(duì)象使用java代理機(jī)制實(shí)現(xiàn),而對(duì)于一般的類使用cglib庫(kù)實(shí)現(xiàn),但spring的實(shí)現(xiàn)還是比較復(fù)雜的,不過抓住了本質(zhì)去看代碼就容易多了。發(fā)現(xiàn)一篇04年寫的《spring源碼分析:實(shí)現(xiàn)AOP》,倒是不用自己再寫了,04年的時(shí)候已經(jīng)有很多人研讀過spring的源碼,而那時(shí)的我還在學(xué)校,對(duì)java半懂不懂的狀態(tài),就算到現(xiàn)在也不敢說真的懂了,繼續(xù)學(xué)習(xí)、努力。文章如下:
我們來看一個(gè)LocalStatelessSessionProxyFactoryBean的例子。首先,定義Stateless EJB的代理,id為ejbServiceProxy:
<bean id="ejbServiceProxy" class="LocalStatelessSessionProxyFactoryBean">
<property name="jndiName">
<value>myEjb</value>
</property>
<property name="businessInterface">
<value>com.mycompany.MyBusinessInterface</value>
</property>
</bean>
這樣,客戶程序并不知道m(xù)yService的實(shí)現(xiàn)細(xì)節(jié),Spring使用FactoryBean完成了兩者之間的解耦。
BeanFactory類的調(diào)用順序
我們暫時(shí)不使用ApplicationContext,以簡(jiǎn)化分析過程。我在這里使用了“Spring AOP編程”的例子,請(qǐng)參照該教程閱讀。首先,編寫測(cè)試用例,代碼如下:
public class AopTest extends TestCase {
XmlBeanFactory factory = null;
ProxyFactoryBean類圖
我的問題
為了完成公司應(yīng)用開發(fā)平臺(tái)的設(shè)計(jì),這幾天一直在研究Spring的擴(kuò)展機(jī)制。Spring的核心無疑是BeanFactory,
ApplicationContext和AOP。在“Spring
AOP編程”教程的例子中,是由ProxyFactoryBean來實(shí)現(xiàn)的。問題來了,普通的bean和FactoryBean的配置完全是一樣的。那
么,BeanFactory是如何區(qū)分普通的Bean和用作Proxy的FactoryBean的?ProxyFactoryBean又是怎樣實(shí)現(xiàn)AOP
功能的?(本文還很不完善,我會(huì)繼續(xù)修改。)
FactoryBean的職責(zé)
FactoryBean在Spring中被當(dāng)成一種特殊的bean,通過實(shí)現(xiàn)FactoryBean接口進(jìn)行擴(kuò)展。FactoryBean的職責(zé)是:
l.封裝了創(chuàng)建對(duì)象或查找對(duì)象的邏輯。
2.提供了一個(gè)中間層,用于支持AOP。
FactoryBean在Spring中被當(dāng)成一種特殊的bean,通過實(shí)現(xiàn)FactoryBean接口進(jìn)行擴(kuò)展。FactoryBean的職責(zé)是:
l.封裝了創(chuàng)建對(duì)象或查找對(duì)象的邏輯。
2.提供了一個(gè)中間層,用于支持AOP。
我們來看一個(gè)LocalStatelessSessionProxyFactoryBean的例子。首先,定義Stateless EJB的代理,id為ejbServiceProxy:
<bean id="ejbServiceProxy" class="LocalStatelessSessionProxyFactoryBean">
<property name="jndiName">
<value>myEjb</value>
</property>
<property name="businessInterface">
<value>com.mycompany.MyBusinessInterface</value>
</property>
</bean>
然后,再將這個(gè)業(yè)務(wù)邏輯服務(wù)對(duì)象注入客戶程序:
<bean id="myAction" class = "samples.myAction">
<property name="myService">
<ref bean="ejbServiceProxy"/>
</property>
</bean>
<bean id="myAction" class = "samples.myAction">
<property name="myService">
<ref bean="ejbServiceProxy"/>
</property>
</bean>
這樣,客戶程序并不知道m(xù)yService的實(shí)現(xiàn)細(xì)節(jié),Spring使用FactoryBean完成了兩者之間的解耦。
準(zhǔn)備代碼分析環(huán)境
1. 安裝Eclipse和Spring IDE。
2. 下載Spring framework源代碼,并導(dǎo)入Eclipse。
3. 在類路徑創(chuàng)建log4j.properties配置文件,設(shè)置如下:
log4j.rootLogger=DEBUG, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{SSS} %p %c{2} - %m%n
4. 編寫TestCase,跟蹤C(jī)onsole窗口的debug信息。
2. 下載Spring framework源代碼,并導(dǎo)入Eclipse。
3. 在類路徑創(chuàng)建log4j.properties配置文件,設(shè)置如下:
log4j.rootLogger=DEBUG, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{SSS} %p %c{2} - %m%n
4. 編寫TestCase,跟蹤C(jī)onsole窗口的debug信息。
FactoryBean源代碼分析
如果bean實(shí)現(xiàn)了FactoryBean接口,BeanFactory將把它作為一個(gè)bean工廠,而不是直接作為普通的bean。正常情況下, BeanFactory的getBean("bean")返回FactoryBean生產(chǎn)的bean實(shí)例,如果要返回FactoryBean本身的實(shí)例, 使用getBean("&bean")的調(diào)用方式。
如果bean實(shí)現(xiàn)了FactoryBean接口,BeanFactory將把它作為一個(gè)bean工廠,而不是直接作為普通的bean。正常情況下, BeanFactory的getBean("bean")返回FactoryBean生產(chǎn)的bean實(shí)例,如果要返回FactoryBean本身的實(shí)例, 使用getBean("&bean")的調(diào)用方式。
在分析ProxyFactoryBean之前,我們先分析BeanFactory,它是Spring Framework的基礎(chǔ)。我們看看它是如何分別處理普通的Bean和FactoryBean的。
BeanFactory分析
BeanFactory類圖

如以上的類圖所示,XmlBeanFactory繼承了AbstactBeanFactory抽象類。AbstactBeanFactory類中使用了
Template
Method設(shè)計(jì)模式,其中的模板方法為getBeanDefinition()和createBean()兩個(gè)抽象方法。其中
AbstractAutowireCapableBeanFactory類實(shí)現(xiàn)了getBeanDefinition()方法,
DefaultAutowireCapableBeanFactory類實(shí)現(xiàn)了getBeanDefinition()方法。當(dāng)調(diào)用getBean()方
法時(shí),AbstractBeanFactory類定義的邏輯分別調(diào)用了這兩個(gè)模板方法。
BeanFactory類的調(diào)用順序
我們暫時(shí)不使用ApplicationContext,以簡(jiǎn)化分析過程。我在這里使用了“Spring AOP編程”的例子,請(qǐng)參照該教程閱讀。首先,編寫測(cè)試用例,代碼如下:
public class AopTest extends TestCase {
XmlBeanFactory factory = null;
protected void setUp() throws Exception {
super.setUp();
InputStream is = new FileInputStream("testaop.xml");
factory = new XmlBeanFactory(is);
}
super.setUp();
InputStream is = new FileInputStream("testaop.xml");
factory = new XmlBeanFactory(is);
}
public void testGetBean() {
Bean bean = (Bean)factory.getBean("bean");
Bean bean = (Bean)factory.getBean("bean");
assertNotNull(bean);
bean.theMethod();
}
}
bean.theMethod();
}
}
1. 首先,XmlBeanFactory使用XmlBeanDefinitionReader讀入testaop.xml配置文件,后者用
XmlBeanDefinitionParser和DefaultXmlBeanDefinitionParser進(jìn)行分析,從中得到
BeanDefinition的信息,并保存在XmlBeanDefinitionReader的BeanDefinitionRegistry變量里。
2. 客戶程序調(diào)用getBean方法時(shí),AbstractBeanFactory首先使用transFormedBeanName方法分析傳入的Bean名稱,判斷客戶程序需要FactoryBean本身,還是它所創(chuàng)建的Bean對(duì)象。
3. 接下來,如果bean被定義為singleton模式,AbstractBeanFactory調(diào)用createBean方法根據(jù) BeanDefinition信息實(shí)例化bean類,然后將該bean實(shí)例傳給getObjectForSharedInstance方法并返回 getObjectForSharedInstance的返回對(duì)象。GetObjectForSharedInstance方法摘要如類圖所示,首先判斷 bean是否繼承了FactoryBean。如果是,返回FactoryBean的getObject方法(下節(jié)我將詳細(xì)分析使用 ProxyFactoryBean如何實(shí)現(xiàn)AOP);如果不是,返回bean對(duì)象。
4. 如果bean被定義為prototype模式,每次客戶程序請(qǐng)求都會(huì)生成新的bean實(shí)例,因此,createBean方法直接實(shí)例化bean對(duì)象并返回。
2. 客戶程序調(diào)用getBean方法時(shí),AbstractBeanFactory首先使用transFormedBeanName方法分析傳入的Bean名稱,判斷客戶程序需要FactoryBean本身,還是它所創(chuàng)建的Bean對(duì)象。
3. 接下來,如果bean被定義為singleton模式,AbstractBeanFactory調(diào)用createBean方法根據(jù) BeanDefinition信息實(shí)例化bean類,然后將該bean實(shí)例傳給getObjectForSharedInstance方法并返回 getObjectForSharedInstance的返回對(duì)象。GetObjectForSharedInstance方法摘要如類圖所示,首先判斷 bean是否繼承了FactoryBean。如果是,返回FactoryBean的getObject方法(下節(jié)我將詳細(xì)分析使用 ProxyFactoryBean如何實(shí)現(xiàn)AOP);如果不是,返回bean對(duì)象。
4. 如果bean被定義為prototype模式,每次客戶程序請(qǐng)求都會(huì)生成新的bean實(shí)例,因此,createBean方法直接實(shí)例化bean對(duì)象并返回。
ProxyFactoryBean如何實(shí)現(xiàn)AOP
ProxyFactoryBean類圖
FactoryBean接口如下圖所示,共有三個(gè)方法getObject,getObjectType,和isSingleton。ProxyFactoryBean實(shí)現(xiàn)了FactoryBean接口,它的相關(guān)類圖如下:

實(shí)現(xiàn)AOP的過程
如上圖所示,ProxyFactoryBean類繼承了AdvisedSupport類,后者繼承了ProxyConfig類并定義了操作advisor 和interceptor的接口,以支持AOP。當(dāng)BeanFactory實(shí)例化ProxyFactoryBean時(shí),根據(jù)配置文件的定義將關(guān)于 advice,pointcut,advisor,所代理的接口和接口實(shí)現(xiàn)類的所有信息傳給ProxyFactoryBean。
如上圖所示,ProxyFactoryBean類繼承了AdvisedSupport類,后者繼承了ProxyConfig類并定義了操作advisor 和interceptor的接口,以支持AOP。當(dāng)BeanFactory實(shí)例化ProxyFactoryBean時(shí),根據(jù)配置文件的定義將關(guān)于 advice,pointcut,advisor,所代理的接口和接口實(shí)現(xiàn)類的所有信息傳給ProxyFactoryBean。
當(dāng)客戶程序調(diào)用BeanFactory的getBean方法時(shí),ProxyFactory使用JdkDynamicAopProxy實(shí)例化
BeanImpl類,并用JdkDynamicAopProxy的invoke方法執(zhí)行advice。至于執(zhí)行advice的時(shí)機(jī),由
ProxyFactoryBean調(diào)用RegexpMethodPointcutAdvisor進(jìn)行判斷。