事務(wù)管理
抽象出一個數(shù)據(jù)訪問的API是不夠的;我們還需要考慮事務(wù)管理。JTA是顯而易見的選擇,但是它是一個直接用起來很笨重的API,因而許多J2EE開發(fā)者感到EJB CMT是對于事務(wù)管理唯一合理的選擇。
Spring提供了它自己對事務(wù)管理的抽象。Spring提供了這些:
通過類似于JdbcTemplate的回調(diào)模板編程管理事務(wù),比起直接使用JTA要容易多了
類似于EJB CMT的聲明式事務(wù)管理,但是不需要EJB容器
Spring的事務(wù)抽象式唯一的,它不綁定到JTA或者任何其他事務(wù)管理技術(shù)。Spring使用事務(wù)策略的概念把程序代碼和底層的事務(wù)架構(gòu)(例如JDBC)解藕。
為什么你要關(guān)心這些?JTA不是所有事務(wù)管理的最好答案嗎?如果你正在編寫僅僅使用一個數(shù)據(jù)庫的程序,你不需要JTA的復雜度。你不關(guān)心XA事務(wù)或者兩階段提交。你甚至不需要提供這些東西的高端應(yīng)用服務(wù)器。但是另一方面,你不會希望在需要和多個數(shù)據(jù)源打交道的時候重寫你的代碼。
假定你決定通過直接使用JDBC或者Hibernate的事務(wù)以避免JTA帶來的額外負擔。一旦你需要處理多個數(shù)據(jù)源,你必須剝開所有的事務(wù)管理代碼并且使用JTA事務(wù)來替代。這不是非常有吸引力的并且導致大部分J2EE程序員,包括我自己,推薦只使用全局JTA事務(wù)。然而使用Spring事務(wù)抽象,你只需要重新配置Spring讓它使用JTA,而不是JDBC或者Hibernate的事務(wù)策略,就一切OK了。這是一個配置上的改變,而不是代碼的改動。因而,Spring使得你能夠自由縮放應(yīng)用。 AOP
最近在應(yīng)用AOP來解決企業(yè)關(guān)注點方面大家有了很大的興趣,例如事務(wù)管理,這些都是EJB所要解決的。
Spring的AOP支持的首要目標是要給POJOs提供J2EE服務(wù)。這類似于JBoss 4的目標,Spring AOP由它能夠在應(yīng)用服務(wù)器之間移植的優(yōu)勢,因而沒有綁死在廠商身上的風險。它既可以在web或者EJB容器中使用,也能夠在WebLogic,Tomcat,JBoss,Resin,Jetty,Orion和許多其他應(yīng)用服務(wù)器和web容器上使用。
Spring AOP支持method interception。所支持關(guān)鍵的AOP概念包括:
Interception:自定義行為能夠在對接口和類的調(diào)用之前和之后插入。這類似于AspectJ術(shù)語中類似的“around advice”。
Introduction:指定advice會導致對象實現(xiàn)額外的接口。這混亂了繼承。
靜態(tài)和動態(tài)的pointcuts:在interception發(fā)生的程序執(zhí)行處指定points。靜態(tài)pointcuts concern函數(shù)簽名;動態(tài)pointcuts也可以在point被求值的地方考慮函數(shù)的參數(shù)。Pointcuts獨立interceptors單獨定義,使得標準interceptor可以應(yīng)用于不同應(yīng)用程序和代碼上下文。
Spring既支持有狀態(tài)(一個advised對象一個實例)也支持無狀態(tài)的interceptors(所有advice使用一個實例)。
Spring不支持field interception。這是一個經(jīng)過深思熟慮的設(shè)計決定。我總是感覺field interception違反了封裝。我比較傾向于把AOP作為補全物,而不是與OOP沖突的東西。如果在5年或者10年后,我們在AOP學習曲線上走得更遠了并且覺得應(yīng)該在程序設(shè)計的桌面上給AOP一個位置,我不會驚訝的。(然而在那個時候基于語言的解決方案例如AspectJ可能比它們今天看來更加具有吸引力。)
Spring使用動態(tài)代理實現(xiàn)AOP(其中存在一個接口)或者在運行時使用CGLIB生成字節(jié)碼(這使得能夠代理類)。兩種方法都能夠在任何應(yīng)用服務(wù)器中使用。
Spring是第一個實現(xiàn)AOP Alliance interfaces的AOP 框架(www.sourceforge.net/projects/aopalliance)。這些是定義在不同AOP框架中能夠互操作interceptors的嘗試。
在TheServerSide和其他地方有一個正在進行但是不是那么引人注目的爭論,就是這種interception是不是“true AOP”。我倒不怎么在意它叫什么;僅僅需要知道它是否在實踐中有用就好了。我也樂于稱它為“declarative middleware”(聲明式中間件)。把Spring AOP認做簡單,輕量級的無狀態(tài)beans的替代物,這樣就不需要monolithic EJB容器了,而這些僅僅是讓你能夠構(gòu)建有你需要的服務(wù)的容器。我不推薦advising任何一個POJO,對local SLSBs的類比有助于你理解推薦的粒度。(然而,與EJB不同的是,在恰當?shù)巧僖姷那闆r下,你可以自由地把Spring的AOP應(yīng)用到粒度更好的對象上。)
因為Spring在實例上advises 對象,而不是在class loader層面上,使用有不同advice的同一個類的多個實例是可能的,或者與advised實例一道使用unadvised 實例。
可能Spring AOP最常見的應(yīng)用是聲明式事務(wù)管理。這是基于前面描述的TansactionTemplate抽象上的,并且可以給任何POJO提供聲明式事務(wù)管理。取決于事務(wù)策略,底層的機制可以是JTA,JDBC,Hibernate或者任何其他提供事務(wù)管理的API。
Spring的聲明式事務(wù)管理類似于EJB CMT,在以下方面有些不同:
事務(wù)管理能夠應(yīng)用于任何POJO。我們推薦業(yè)務(wù)對象實現(xiàn)接口,但是這只是一個好的編程習慣的問題,而不是由框架強制的。
通過使用Spring的事務(wù)API能夠在事務(wù)性POJO中實現(xiàn)編程回調(diào)。我們?yōu)榇颂峁╈o態(tài)的方法,使用ThreadLoacal變量,因而你不需要傳播諸如EJBContext這樣的context對象來確保回滾。
你可以聲明式地定義“回滾規(guī)則”。EJB不會在未捕捉程序異常的時候自動回滾(僅僅在unchecked exceptions和其他Throwables的時候),應(yīng)用程序開發(fā)者經(jīng)常需要在任何異常發(fā)生時回滾。Spring事務(wù)管理讓你能夠聲明式地指定什么異常什么子類能夠?qū)е伦詣踊貪L。缺省的行為和EJB是一致的,但是你能夠在checked和unchecked異常時自動回滾。這個在最少化自編程回調(diào)代碼方面有很大好處,而回調(diào)依賴于Spring的事務(wù)API(因為EJB的編程回調(diào)時在EJBContext中完成的)。
事務(wù)管理不綁定于JTA。如前面解釋過的,Spring的事務(wù)管理能夠在不同事務(wù)策略中使用。
當然還可以使用Spring AOP實現(xiàn)程序特有的aspects。取決于你對AOP概念的接受程度,決定你是否選擇這么做,而不是Spring的能力,但是它確實非常有用。我們所見過的成功例子包括:
自定義的security interception,當安全檢查的復雜度超出了J2EE安全架構(gòu)的能力的時候
在開發(fā)中使用的調(diào)試和profiling aspects
發(fā)送email通知管理員用戶不尋常的舉動的Interceptors
程序自定的aspects能夠成為消除需要許多函數(shù)的樣板代碼的有利武器。
Spring AOP透明地與Spring BeanFactory概念集成。包含一個來自Spring BeanFactory對象地代碼不需要知道它是還是不是advised。和任何對象一樣,契約實在接口和對象實現(xiàn)中定義的。
下面的XML片斷展示了如何定義一個AOP代理:
代碼: |
<bean id="myTest" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="proxyInterfaces"> <value>org.springframework.beans.ITestBean</value> </property> <property name="interceptorNames"> <list> <value>txInterceptor</value> <value>target</value> </list> </property> </bean>
|
注意bean類的定義總是AOP框架的ProxyFactoryBean,雖然bean的類型在引用中使用或者由BeanFactory的getBean()方法返回時依賴的是代理接口。(多個代理方法是被支持的。)ProxyFactoryBean的“interceptorNames”屬性需要一個字符串列表。(因為如果代理是一個“prototype”而不是singleton,有狀態(tài)interceptors可能需要創(chuàng)建新的實例,所以必須使用Bean的名字而不是bean的引用。)列表中的名字可以是interceptor或者pointcuts(interceptors和有關(guān)它們合適被使用的信息)。列表中的“target”值自動創(chuàng)建一個“invoker interceptor”封裝target對象。實現(xiàn)代理接口的是在factory中的bean的名字。這個例子中的myTest可以和其他bean factory中的bean一樣使用。例如,其他對象可以使用<ref>元素引用它而且這些引用是由Spring IoC設(shè)置的。
還可以不用BeanFactory,編程構(gòu)建AOP代理,雖然這個很少用得上:
代碼: |
TestBean target = new TestBean(); DebugInterceptor di = new DebugInterceptor(); MyInterceptor mi = new MyInterceptor(); ProxyFactory factory = new ProxyFactory(target); factory.addInterceptor(0, di); factory.addInterceptor(1, mi); // An "invoker interceptor" is automatically added to wrap the target ITestBean tb = (ITestBean) factory.getProxy();
|
我們相信最好把程序裝配從Java代碼中移出來,而AOP也不例外。
Spring在它的AOP能力方面的直接競爭者是Jon Tirsen的Nanning Aspects(http://nanning.codehaus.org)。
我覺得AOP作為EJB的替代無提供企業(yè)服務(wù)這個用法方面的進步是重要的。隨著時間,這將成為Spring很重要的關(guān)注點。
posted on 2005-10-26 15:56
Sung 閱讀(239)
評論(0) 編輯 收藏 所屬分類:
Java