權(quán)限、事務(wù)、日志處理如果混雜在業(yè)務(wù)代碼之中會使整個代碼變得非常復(fù)雜而且可讀性很差,難以修改重構(gòu)。
面向?qū)ο蟮姆治龊驮O(shè)計引入了繼承、抽象和多態(tài)等概念,由此為我們提供了降低軟件復(fù)雜性的工具。但是,開發(fā)人員在軟件設(shè)計過程中仍然經(jīng)常會面對無法用面向?qū)ο筌浖_發(fā)技術(shù)輕易解決的問題。這些問題之一就是如何處理應(yīng)用程序中的橫切關(guān)注點(Cross-cutting concerns)。
1、橫切關(guān)注點
關(guān)注點就是設(shè)計人員感興趣的某一概念或區(qū)域。例如,在一個訂貨系統(tǒng)中,核心關(guān)注點可能是訂單處理和生產(chǎn),而系統(tǒng)關(guān)注點可能是事務(wù)處理和安全管理。
橫切關(guān)注點是影響多個類或模塊的關(guān)注點,即未能很好地局部化和模塊化的關(guān)注點。
橫切關(guān)注點的表現(xiàn)有:
·代碼糾結(jié)—當一個模塊或代碼段同時管理多個關(guān)注點時發(fā)生這種情況。
·代碼分散—當一個關(guān)注點分布在許多模塊中并且未能很好地局部化和模塊化時發(fā)生這種情況。
這些現(xiàn)象會從幾個方面影響軟件;例如,它們會導(dǎo)致軟件難以維護和重用,并且難以編寫和理解。
2、關(guān)注點的隔離
面向方面編程試圖通過引入“關(guān)注點的隔離”這一概念來解決這些問題。采用這一概念,可以以一種模塊化而且適當局部化的方式實現(xiàn)關(guān)注點。AOP解決這個問題的辦法是在設(shè)計空間中增加額外一維,并且引入了一些構(gòu)造,這些構(gòu)造使我們能夠定義橫切關(guān)注點,將它們轉(zhuǎn)移進新的維,并且以模塊化方式將它們打 包。
聲明式的AOP事務(wù)配置如下:
<bean id="nodeTarget"
class="com.daosheng.service.impl.NodeManagerImpl"
singleton="true"
lazy-init="default"
autowire="default" dependency-check="default">
<property
name="dao">
<ref
local="nodeDAO" />
</property>
</bean>
<bean
id="nodeManager"
class="com.daosheng.cms.right.RightTransactionProxyFactoryBean"
singleton="true"
lazy-init="default" autowire="default"
dependency-check="default">
<property
name="transactionManager">
<ref
local="transactionManager" />
</property>
<property
name="target">
<ref
local="nodeTarget" />
</property>
<property
name="transactionAttributes">
<props>
<prop
key="insert*">
PROPAGATION_REQUIRED,-ApplicationException
</prop>
<prop
key="update*">
PROPAGATION_REQUIRED,-ApplicationException
</prop>
</props>
</property>
</bean>
|
其實在注冊nodeManager時注冊的實際類不是自己開發(fā)的NodeManagerImpl類而是注冊的RightTransactionProxyFactoryBean代理工廠類。在其它類里調(diào)用的nodeManager方法實際上是先調(diào)用的此代理工廠類的加入橫切點代碼(事務(wù)處理代碼)然后在調(diào)用的NodeManagerImpl的相應(yīng)方法,這樣就實現(xiàn)了NodeManagerImpl類里不用操心事務(wù)問題,而實際的事務(wù)由加入在切點的Advice來完成。其在真正方法執(zhí)行前啟動事務(wù),執(zhí)行后提交事務(wù)(commit),如果出現(xiàn)異常則回滾(rollback)。
代理工廠類是采用jdk4以上自帶的動態(tài)代理機制實現(xiàn)的。
框架的AOP中提供了4種處理切入類型:around,before,after,introduction.顧名思義,
1) around是針對具體的某個切入點的方法(比如,現(xiàn)在有個OrderBook方法,around的切入類型是就這個方法的內(nèi)部調(diào)用,是通過java的元
數(shù)據(jù),在運行時通過Method.invoke來調(diào)用,具有返回值,當發(fā)生意外的時候會終止.記住的一點是,返回值.);
2)before是在方法調(diào)用前調(diào)用(在OrderBook方法前調(diào)用,但是沒有返回值,同時在通常意外情況下,會繼續(xù)運行下一步方法.記住的一點是沒有返回值);
3)after和before剛好相反,沒有什么特別的地方.
4)introduction是一個更加特殊的,但功能更加強大的切入類型.比如(你現(xiàn)在有Book對象,Computer對象,還有幾十個這種業(yè)務(wù)對象,現(xiàn)在你希望在每個這樣的對象中都加入一個記錄最后修改的時間.但是你又不希望對每個類都進行修改,因為太麻煩了,同時更重要的一點,破壞了對象的完整性,說不定你以后又不需要這個時間數(shù)據(jù)了呢.框架AOP為了專門實現(xiàn)這種思想提供了一個切入處理,那就是introduction.introduction可以為動態(tài)加入某些方法,這樣可以在運行時,強制轉(zhuǎn)換這些對象,進行插入時間數(shù)據(jù)的動作,更深的內(nèi)幕就是C++虛函數(shù)中的vtable思想).
下面時序圖為事務(wù)在整個各層代碼協(xié)作過程中啟動和提交的過程。每個Manager或者DAO實體可能是開發(fā)的實際類也可以是代理類。