Spring框架中成功吸引人的一點就是容器事務的管理,提供了一個輕量級的容器事務處理,針對的對象是普通的java類,使用Spring事務管理的話,你可以按照自己的業務把一些相關的方法納入其事務管理裡面,這就避免了程序員在處理事務的過程中繁瑣的工作.同時這些也是ejb2.X規范裡面吸引人的一點,這在spring裡面都很好的提供.雖然在跨容器的事務管理,spring裡面並沒有提供,但是對於一般的web程序來說,也不需要僅僅為了那些功能而不得不使用ejb。不過,最近jboss的嵌入式的ejb容器也可以做的更小了,也是開源中的選擇之一.無論技術是怎樣發展的,當前,我們先來研究其中AOP實現的方法。
事實上,Spring中的事務處理是通過AOP思想來實現的,Spring AOP與Aspect J和JBoss具有很大的不同,首先,使用Spring AOP框架的用戶要記住的一點是,Spring AOP針對的是方法層次上的實現,而其他兩者對字段也提供了支持.說到Spring AOP的內幕,其實也不難,對於有接口的類,使用的是Java內部類提供的Proxy;而對於那些不實現接口的類,使用的是cglib庫,動態創建一個子類來實現.
在Spring AOP中提供了4種處理切入類型:around,before,after,introduction.
1)around是針對具體的某個切入點的方法(比如,現在有個OrderBook方法,around的切入類型是就這個方法的內部調用,是通過java的元數據,在運行時通過Method.invoke來調用,具有返回值,當發生意外的時候會終止.記住的一點是,返回值.);
2)before是在方法調用前調用(在OrderBook方法前調用,但是沒有返回值,同時在通常意外情況下,會繼續運行下一步方法.記住的一點是沒有返回值);
3)after和before剛好相反,沒有什麼特別的地方.
4)introduction是一個更加特殊的,但功能更加強大的切入類型.比如(你現在有Book對象,Computer對象,還有幾十個這種業務對象,現在你希望在每個這樣的對象中都加入一個記錄最後修改的時間.但是你又不希望對每個類都進行修改,因為太麻煩了,同時更重要的一點,破壞了對象的完整性,說不定你以後又不需要這個時間數據了呢...這時怎麼辦呢?Spring AOP就為你專門實現這種思想提供了一個切入處理,那就是introduction.introduction可以為你動態加入某些方法,這樣可以在運行時,強制轉換這些對象,進行插入時間數據的動作,更深的內幕就是C++虛函數中的vtable思想).不過這種動態是以性能作為代價的,使用之前要慎重考慮,這裡我們談的是技術,所以就認為他是必需的。
好,現在我們就拿第四種來進行舉例說明Spring AOP的強大之處:
1)假設創建了一個BookService接口及其實現方法(你自己的業務對象):
//?$ID:BookService.java Created:2005-11-6 by Kerluse Benn
package com.osiris.springaop;
public interface BookService {
public String OrderComputerMagazine(String userName,String bookName);
public String OrderBook(String userName,String bookName);
}
//?$ID:BookServiceImpl.java Created:2005-11-6 by Kerluse Benn
package com.osiris.springaop;
public class BookServiceImpl implements BookService{
public String OrderBook(String name,String bookName) {
// TODO Add your codes here
String result=null;
result="訂購"+bookName+"成功";
return result;
}
public String OrderComputerMagazine(String userName, String bookName) {
// TODO Add your codes here
String result=null;
result="訂購"+bookName+"成功";
return result;
}
}
2) 事實上你還有很多這樣的對象,現在我們希望在每個對象中添加我們的功能最後修改的時間,功能如下:
//?$ID:IAuditable.java Created:2005-11-7 by Kerluse Benn
package com.osiris.springaop.advices.intruduction;
import java.util.Date;
public interface IAuditable {
void setLastModifiedDate(Date date);
Date getLastModifiedDate();
}
3) 因為我們使用的切入類型是introduction,Spring AOP為我們提供了一個描述這種類型的接口IntroductionInterceptor,所以我們的切入實現處理,也需要實現這個接口:
//?$ID:AuditableMixin.java Created:2005-11-7 by Kerluse Benn
package com.osiris.springaop.advices.intruduction;
import java.util.Date;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.IntroductionInterceptor;
public class AuditableMixin implements IAuditable,IntroductionInterceptor{
private Date lastModifiedDate;
public Object invoke(MethodInvocation m) throws Throwable {
// TODO Add your codes here
if(implementsInterface(m.getMethod().getDeclaringClass())){
return m.getMethod().invoke(this,m.getArguments());
//invoke introduced mthod,here is IAuditable
}else{
return m.proceed(); //delegate other method
}
}
public Date getLastModifiedDate() {
// TODO Add your codes here
return lastModifiedDate;
}
public void setLastModifiedDate(Date date) {
// TODO Add your codes here
lastModifiedDate=date;
}
public boolean implementsInterface(Class cls) {
// TODO Add your codes here
return cls.isAssignableFrom(IAuditable.class);
}
}
輸出結果:
訂購Professional C#成功 訂購時間為Mon Nov 07 11:35:20 CST 2005
訂購Expert j2ee one-on-one成功 訂購時間為Mon Nov 07 11:35:30 CST 2005
看見上面黑體字:
IAuditable auditable=(IAuditable)bookService;
由於bookService對象事實上已經實現了IAuditable接口,通過Spring AOP的introduction切入實現,所以在運行時(熟悉C++的vtable模型的可以在大腦裡想一下)可以轉換,我們就可以隨意添加自己的接口方法了。
好了,關於Spring AOP就介紹到這了,其他相關的內容可以參考相應的書籍,這篇文章的目的主要是為了介紹一下AOP思想應用的強大之處.具體的相關應用還包括用戶操作驗證等等。