摘要 本文對spring框架中所包含的aop思想以及事務管理進行了分析,并通過對一個業務對象實現加鎖/解鎖的操作,說明了動態代理模式的可行性與有效性。 
  關鍵詞 aop;橫切關注點;控制反轉;動態代理
  引言
  aspect oriented programming(aop)是近年來計算機技術中比較熱門的話題之一。其發展歷史從學術領域和研發機構的運用開始,目前流行的spring應用程序框架將aop思想融入了整個框架的設計開發與應用當中。使用spring框架固然給我們的編程帶來了好處與便利,但是同時存在著一個問題,對于初學者來說,所謂的“控制反轉”,不是一個能夠望文生義的好名稱,“依賴注入”也是一樣,也正是因為這樣,不少初學者很難在短時間內理解和掌握這些名字和他們的用法,而要使用aop的功能也需要理解aop,也比較難。基于以上原因,我們就會想到,能否簡單地將spring框架中運用到的優秀的理念,巧妙的運用到我們需要使用的地方,而又繞過不容易上手的spring框架,做到一舉兩得呢?本文就將圍繞著上述提出的問題給出作者的看法和觀點。
  aop思想與面向方面的編程
  aop實際是gof四人組設計模式的一種擴展,設計模式所追求的是降低代碼之間的耦合度,增加程序的靈活性和可重用性,aop實際上就是設計模式所追求的目標的一種實現。所謂的分離關注就是將某一通用的需求功能從不相關的類之中分離出來;同時,能夠使得很多類共享一個行為,一旦行為發生變化,不必修改很多類,只要修改這個行為就可以。aop就是這種實現分散關注的編程方法,它將“關注”封裝在“方面”中。
  面向對象的編程(oop)方法是在面向過程的編程方法基礎上進行的改進,而面向方面編程(aop)方法又是在面向對象編程(oop)方法的基礎上進行改進而來的一種創新的軟件開發方法。aop和oop雖然在字面上十分相似,但是卻是面向不同領域的兩種設計思想。oop(面向對象編程)針對問題領域中以及業務處理過程中存在的實體及其屬性和操作進行抽象和封裝,面向對象的核心概念是縱向結構的,其目的是獲得更加清晰高效的邏輯單元劃分;而aop則是針對業務處理過程中的切面進行提取,例如,某一個操作在各個模塊中都有涉及,這個操作就可以看成“橫切”存在于系統當中。在許多情況下,這些操作都是與業務邏輯相關性不強或者不屬于邏輯操作的必須部分,而面向對象的方法很難對這種情況做出處理。aop則將這些操作與業務邏輯分離,使程序員在編寫程序時可以專注于業務邏輯的處理,而利用aop將貫穿于各個模塊間的橫切關注點自動耦合進來。aop所面對的是處理過程中的某個步驟或階段,對不同的階段領域加以隔離,已獲得邏輯過程中各部分之間低耦合性的隔離效果,其與面向方面編程在目標上有著本質的差異。aop的核心思想就是將應用程序中的業務邏輯處理部分同對其提供支持的通用服務,即所謂的“橫切關注點”進行分離,這些“橫切關注點”貫穿了程序中的多個縱向模塊的需求。
  使用aop機制進行開發,首先要對方面進行了解,將需求分解成一般關注點和橫切關注點,即將核心模塊級的關注點和系統級的橫切關注點分離;然后各自獨立的實現這些關注點;最后用工具將業務邏輯代碼和橫切關注點代碼編織到一起,形成最終的程序。通過面向方面的編程可以減少編碼時間和重復。
  目前已經形成的spring框架
  1、spring框架的特點
  spring框架目前如此流行,一方面的原因在于spring提供了一套全面并且十分成熟的輕型應用程序基本框架,并且對復雜的應用開發提供了有力的支持。除此之外,從實際應用開發角度來看,spring最大的優勢在于它是從實際項目開發經驗中抽取的,其提供了豐富的類庫,可大大節省編碼量,它是一種高效的、可高度重用的應用框架。spring框架中目前最吸引人也是該應用框架最具特色的地方就是名為控制反轉(ioc=inverse of control)或者依賴注入(di=dependence injection)的設計思想,這是一種相當優秀的設計思想,即“好萊塢”原則:不用你主動來找我,我會通知你。但是,僅僅憑借著這樣一個單純的設計模式并不能使得spring如此成功,spring最成功的地方,還是目前使用最為廣泛的aop應用,也就是spring中基于aop實現的業務管理機制,也正是由于這一點,使得spring aop成為應用框架中極其閃光的一個亮點。
  2、aop思想在spring框架中的體現
  文章前面已經講述了aop的概念以及什么叫做所謂的“橫切”關注點,事務管理就是j2ee應用中一個橫切多個對象的橫切關注點的例子。
  2.1 事務管理
  對于j2ee應用程序而言,事務的處理一般有兩種模式:依賴特定事務資源的事務處理與依賴容器的參數化事務管理。在這里我們略去對第一種處理方式的說明,直接對第二種方式,即依賴容器的參數化事務管理來闡述筆者的觀點。
  spring事務管理究竟能帶給我們什么?
  了解spring的人們都知道,對于傳統的基于事務資源的事務處理而言,spring并不會產生什么影響,我們照樣可以成功編寫并且運行這樣的代碼。
  對于依賴容器的參數化事務管理而言,spring則可以用來幫助實現對事務的管理而無須使用ejb。spring本身也是一個容器,只是相對ejb容器所要付出的代價而言,spring屬于輕量級容器,它能夠替代ejb,通過使用aop來提供聲明式事務管理,即可通過spring實現基于容器的事務管理(從本質上來講,spring的事務管理是基于動態aop)。spring與ejb最大的區別在于:第一,spring可以為任意的java class實現事務管理而無須轉換成標準的ejb;第二,spring事務管理并不依賴特定的事務資源從而使得系統的應用與部署更佳靈活。
  2.2動態代理機制的實現
  spring框架中所提供的aop支持,是基于動態aop機制實現的,即通過動態proxy模式,在目標對象的方法調用前后插入相應的處理代碼。aop代理可以是基于jdk動態代理,也可以是基于cglib代理。spring默認使用的是基于java dynamic proxy模式實現,這樣任何的接口都能被代理。基于spirng框架的應用程序開發,程序員會有一種自然的傾向性來實現面向接口編程而不是類,業務對象通常也是實現一個或者多個接口,這也是一種良好的編程習慣。spring也可以基于cglib實現aop代理,這樣所代理的是類而不是接口。如果一個業務對象沒有實現某一個接口,那么cglib將被使用。
  我們先來分析一下spring事務管理機制的實現原理。由于spring內置aop默認使用動態代理模式實現,我們就先來分析一下動態代理模式的實現方法。動態代理模式的核心就在于代碼中不出現與具體應用層相關聯的接口或者類引用,如上所說,這個代理類適用于任何接口的實現。下面我們來看一個例子。 public class txhandler implements invocationhandler {
private object originalobject;
public object bind(object obj) {
 this.originalobject = obj;
 return proxy.newproxyinstance(obj.getclass().getclassloader(),obj.getclass().getinterfaces(),this);
}
public object invoke(object proxy, method method, object[] args)
throws throwable {
 object result = null;
 if (!method.getname().startswith("save")) {
  usertransaction tx = null;
  try {
   tx = (usertransaction) (new initialcontext().lookup("java/tx"));
   result = method.invoke(originalobject, args);
   tx.commit();
  } catch (exception ex) {
   if (null != tx) {
    try {
     tx.rollback();
    } catch (exception e) {
   }
  }
 }
} else {
 result = method.invoke(originalobject, args);
}
return result;
}
}
  下面我們來分析一下上述代碼的關鍵所在。
  首先來看一下這段代碼:
return proxy.newproxyinstance(
 obj.getclass().getclassloader(),obj.getclass().getinterfaces(),this);
  java.lang.reflect.proxy.newproxyinstance方法根據傳入的接口類型(obj.getclass.getinterfaces())動態構造一個代理類實例返回,這也說明了為什么動態代理實現要求其所代理的對象一定要實現一個接口。這個代理類實例在內存中是動態構造的,它實現了傳入的接口列表中所包含的所有接口。
  再來分析以下代碼:
public object invoke(object proxy, method method, object[] args)
throws throwable {
 ……
 result = method.invoke(originalobject, args);
 ……
 return result;
}
  invocationhandler.invoke方法將在被代理類的方法被調用之前觸發。通過這個方法,我們可以在被代理類方法調用的前后進行一些處理,如代碼中所示,invocationhandler.invoke方法的參數中傳遞了當前被調用的方法(method),以及被調用方法的參數。同時,可以通過method.invoke方法調用被代理類的原始方法實現。這樣就可以在被代理類的方法調用前后寫入任何想要進行的操作。
  spring的事務管理機制實現的原理,就是通過這樣一個動態代理對所有需要事務管理的bean進行加載,并根據配置在invoke方法中對當前調用的方法名進行判定,并在method.invoke方法前后為其加上合適的事務管理代碼,這樣就實現了spring式的事務管理。spring中的aop實現更為復雜和靈活,不過基本原理是一致的。
  3.aop思想與動態代理模式的應用實例
  綜上我們分析了spring框架的事務管理機制的基本現實原理。盡管spring框架集中體現了當前流行框架中未曾關注到的一些內容,但是,spring框架存在晦澀難懂的致命問題。以上通過對spring框架的一些基本實現原理的研究,給我們帶來了一些啟示。我們如果不直接使用龐大的spring框架,而是將融入spring框架中的aop思想直接應用于程序中,既繞過了spring框架這個高門檻,又利用了spring框架中先進的設計理念,這樣便達到了一舉兩得的目的。
  下面我們來看一段代碼,我們來編寫一個dynamic proxy based aop實現的實例。假設現在有一個userdao接口和以及其實現類userdaoimp。
userdao.java:
public interface userdao {
 public void saveuser(user user);
}
userdaoimp.java:
public class userdaoimp implements userdao{
 public void saveuser(user user) {
  ……
 }
}
  我們需要在saveuser方法中添加對一個業務對象的鎖,比如在saveuser前后加鎖和解鎖。在不影響外部邏輯和不對現有的代碼做任何改動的前提下,代理模式是一個不錯的選擇。但是如果有多個類似的接口,面對每個接口都要實現一個類似的proxy,實在是一個煩瑣無味的苦力過程。回想一下spring在處理這個問題上的設計理念我們不難想到,使用動態代理模式,是這個問題的一個聰明的解決方法。
public class aophandler implements invocationhandler {
 private static log logger = logfactory.getlog(aophandler.class);
 private list interceptors = null;
 private object originalobject;
 public object bind(object obj) {
  this.originalobject = obj;
  return proxy.newproxyinstance(obj.getclass().getclassloader(),obj.getclass().getinterfaces().this);
 }
 public object invoke(object proxy, method method, object[] args) throws throwable{object result=null
  if(method.getname.startswith(“saveuser”)){
   lock();
   result=method.invoke(this.originalobject,args);
   unlock();
  }
  return result;
 }
 private void lock(){
  logger.info(“lock object!”);
 }
 private void unlock(){
  logger.info(“unlock object!”);
 }
}
  上述代碼中并沒有出現與具體應用層相關聯的接口以及類的引用,所以對所有的類都適用。這就解決了用靜態proxy類實現所產生的弊端。
  總結與展望
  以上我們討論了spring框架基于動態aop機制實現以及動態代理機制的應用,圍繞著aop的實現與應用,一直有一個熱門的話題,即權限管理。spring框架目前對aop的支持做得相當出色,但是一直有一個尷尬的問題尚未解決,那就是目前還沒有一個完備的權限管理組件。仔細想想,這并不是aop的瓶頸,而是因為權限管理的形式過于靈活和復雜多變,系統中的權限管理邏輯多種多樣各不相同,我們很難做出一個統一的管理與操作。另一方面,權限管理作為一個獨立的切面顯得過于龐大,需要進一步切分設計,設計過程復雜,實現難度較大。所以我們還在期待著aop思想在權限管理方面能有突破性的應用與擴展。