Spring Aop Step-By-Step 學習筆記(上)
最近由于工作需要,要求掌握關于 Spring 方面的東西。所以花了兩個星期的時間來學習 Spring 的基本知識,主要包括 Ioc 和 Aop 兩方面。
本文為筆者的 Spring 在 Aop 方面的學習筆記,主要結合了 Spring In Action 第三章 和 Spring-Reference 第五章 為學習向導。根據自己的理解和書中的實例來一步一步完成對于在 Spring 中 Aop 方面的編程。其中基礎部分 Ioc 需要讀者自己參考資料了解,本文將不做描述。
說明:我將盡量縮短程序長度,在程序部分將減少注釋說明,重點要讀者自己根據上下文和程序結果理解體會,具體 api 信息請讀者自己參考 Spring-api 文檔和相關資料。
一. 準備工作:
1. 開發環境:
l 適合人群:
要了解 Spring Ioc ,對 Spring- Aop 可以不了解或者僅僅熟悉 Aop 概念,未參與 Spring Aop 開發實戰的初學者。同時也希望高手對于本文的不足或理解錯誤之處給予指點,謝謝。
l 開發環境:
JDK 1.4_2
l 開發工具:
Eclipse 3.12 (未采用任何插件,主要是為初學者熟悉和理解 xml 文檔的配置)
l 所需組件:
Spring-Framework-1.2.8
下載地址:
2. 建立工程:
首先用 Eclpse 建立一個普通 java 項目,導入 jar 文件到編譯環境中,如下:
a) Spring.jar 為 Spring 的核心 jar 文件,必須;
b) Commons-loggin.jar 日志文件,必須;
c) Cglib.jar 動態代理文件,不是必須(本文需要);
d) Jak-oro.jar 使用 Perl 和 Awk 正則表達式進行文本解析工具,不是必須(本文需要);
建立工程如下:
好了,下來我們開始我們的 Spring-aop 之旅;
二. Spring -Aop 入門
AOP 全名 Aspect-oriented programming 。 Spring framework 是很有前途的 AOP 技術。作為一種非侵略性的,輕型的 AOP framework ,你無需使用預編譯器或其他的元標簽,便可以在 Java 程序中使用它。這意味著開發團隊里只需一人要對付 AOP framework ,其他人還是像往常一樣編程。
關鍵性概念:
1) Advice 是代碼的具體實現,例如一個實現日志記錄的代碼。
2) Pointcut 是在將 Advice 插入到程序的條件。
3) advisor 是把 pointcut 和 advice 的組合在一起裝配器。
圖例:
你的程序可能如上,現在要在三個流程上同時加入日志控制和權限控制,如下:
你的程序可能如上,現在要在三個流程上同時加入日志控制和權限控制,如下:
其中拿日志為例,日志控制和流程之間的穿插點處叫做連接點( Joinpoint ),而 Advice 就是我們日志處理的具體代碼, Pointcut 就是定義一個規則,對三個和業務有關的連接點進行過濾和匹配(例如我們對于業務 1 不做日志處理)。 Advisor 就是將符合的規則的剩下的兩個連接點和具體的日志記錄代碼組合在一起。
三. Spring-Aop 前置通知、后置通知、環繞通知、異常通知實現
我以 Spring In Action 提供的例子進行二次改造,完成我們自己的流程。業務流程很簡單,顧客到商店買東西,店員根據顧客的需要給于顧客提供服務。實現方法前插入,方法后插入,環繞,異常四種。
代碼:
建立一個用戶類;










三個產品




























建立一個接口;



















































































環繞通知的實現,必須實現invoke方法,通過調用invoke.proceed()手工調用對象方法:


























前置通知的實現;
























































自定義的異常接口;













































































沒有更多的果醬異常;


























運行實例類;

public class RunDemo
{


public static void kwikEMart()
{

ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("demo/kwikemart.xml");

//如果你想通過類來引用這個的話,就要用到CGLIB.jar了,同時在代理工廠里面設置:
//<property name="proxyTargetClass" value="true" />
KwikEMart akem = (KwikEMart) context.getBean("kwikEMart");

try
{
akem.buySquish(new Customer());
akem.buyPepper(new Customer());
akem.buyCheese(new Customer());

} catch (KwikEMartException e)
{
//異常已經被截獲了,不信你看控制臺!~;
}
}


public static void main(String[] args)
{
kwikEMart();
}
}
Xml 文件配置:

































Xml 文件配置:
















































這個例子東西很多,不過每個類的代碼都不大。如果你對 org.springframework.aop.framework.ProxyFactoryBean 不是很了解的話可以看我下篇尾處的介紹。 讀清楚之后,我們運行RunDemo 類,查看控制臺結果,如下:
店員::Hello 悠~游! . How are you doing?
店員:悠~游! ,Can I help you ?
-- 我想買:果醬!
店員:OK! 悠~游!.give you!
店員:Thank you 悠~游! . Come again!
店員::Hello 悠~游! . How are you doing?
店員:悠~游! ,Can I help you ?
-- 我想買:胡椒粉!
店員:OK! 悠~游!.give you!
店員:Thank you 悠~游! . Come again!
店員::Hello 悠~游! . How are you doing?
店員:悠~游! ,Can I help you ?
-- 我想買:奶酪!
店員:OK! 悠~游!.give you!
店員:Thank you 悠~游! . Come again!
我們將 kwikEMartTarget 里面的注釋去掉,測試異常實現,如下:
店員::Hello 悠~游! . How are you doing?
店員:悠~游! ,Can I help you ?
系統:NoMoreSquisheesException異常截獲了: NoMoreSquishException 異常!
好好理解一下,我就不廢話了,我們進行下一節。
四. Spring-Aop 之Pointcut+advice+Advisor 實現
我們修改我們的xml文檔后如下:





















































運行,結果如下:
店員:悠~游! ,Can I help you ?
--我想買:果醬!
店員:OK! 悠~游!.give you!
店員:悠~游! ,Can I help you ?
--我想買:胡椒粉!
店員:OK! 悠~游!.give you!
店員:悠~游! ,Can I help you ?
--我想買:奶酪!
店員:OK! 悠~游!.give you!
在這里簡單說明一下xml文檔:nameMatchfilterPointcut和regexpFilterPointcut 是我們自己定義好規則的Pointcut。nameMatchfilterPointcut 根據mappedName來設置過濾規則, regexpFilterPointcut則是用pattern來設置過濾規則。runDemofilterPointcutAdvisor則將我們的Pointcut和advice組合在一起。
讀者可以自己修改runDemofilterPointcutAdvisor的pointcut來切換不同的Pointcut。如果需要RegexpMethodPointcut 的子類的實現,必須要oro包支持。(注:RegexpMethodPointcut有倆個子類的實現,JdkRegexpMethodPointcut和Perl5RegexpMethodPointcut)。
但是,如果我們想讓我們的Advisor同時實現多個Pointcut+advice怎么辦呢?利用Spring In Action里面的實例,我們來自己實現我們的Pointcut。
代碼:


















































在xml中,加入下面代碼:




















運行的結果請讀者自己試驗。這個時候您可能在想,這些pointcut都是Spring自己的實現,我們能否自己來定義我們自己規則的pointcut呢?當然可以!~
代碼:

/** *//**
*
* 自己定義的靜態切入點
* 滿足條件是:當傳入的數字大于1塊錢的時候才可以;
*
* @author 悠~游
* @since 2006-06-22
* @link www.uusam.com
*/

public class MyPointcut extends StaticMethodMatcherPointcut implements Serializable
{

private static final long serialVersionUID = -101281038294508751L;

private int money = 0;


/** *//**
* 實現方法,業務邏輯為:根據輸入的錢數和動作(必須是以buy開頭的方法),來確定是否有錢購買商品,買完之后去掉商品的價格;
*/

public boolean matches(Method method, Class targetClass)
{

if (method.getName().indexOf("buyCheese") == 0 && money >= 100)
{
money -= 100;
return true;

} else if (method.getName().indexOf("buyPepper") == 0 && money >= 5)
{
money -= 5;
return true;

} else if (method.getName().indexOf("buySquish") == 0 && money >= 10)
{
money -= 10;
return true;
}
System.out.println("門衛:你要買的東西太貴,你的錢 "+money+" 太少!~ ,取消服務!");
return false;
}


public void setMoney(int money)
{
this.money = money;
}

}




















































這個就是我們自己定義的靜態Pointcut,主要實現自己的matches方法。看看如何加入到我們的XML文檔中:






很簡單不是么?我們定義一個數字,就是用戶的money,進入商店時候兜里的錢^_^。同樣修改我們的myUnionPointcut里面的pointcuts,加入我們的pointcut。










當上面兩個Pointcut定義的規則不通過的時候,程序開始校驗我們的myPointcut。運行,結果如下:
店員:悠~游! ,Can I help you ?
--我想買:果醬!
店員:OK! 悠~游!.give you!
店員:悠~游! ,Can I help you ?
--我想買:胡椒粉!
店員:OK! 悠~游!.give you!
門衛:你要買的東西太貴,你的錢 85 太少!~ , 取消服務!
--我想買:奶酪!//服務員沒了...
好了,是不是我們想要的結果呢?呵呵。
同時,Spring 提供動態Pointcut。關于動態的說明我就不在熬述了,我們這里只關心具體Spring帶給我們的具體實現方法,具體應用請讀者自己斟酌使用。














運行,結果如下:
店員:悠~游! ,Can I help you ?
--我想買:果醬!
店員:OK! 悠~游!.give you!
店員:悠~游! ,Can I help you ?
--我想買:胡椒粉!
店員:OK! 悠~游!.give you!
店員:悠~游! ,Can I help you ?
--我想買:奶酪!
店員:OK! 悠~游!.give you!
動態切入點是根據當前堆棧信息進行方法匹配的一種規則,讀者可以自己修改demo.RunDemo,如java.lang.Integer,來看看結果。
--我想買:果醬!
--我想買:胡椒粉!
--我想買:奶酪!
到這里能夠讀下來已經很不容易了,呵呵。還是站起來走動一下吧,接下來我們將搞定其他的一些東東。
posted on 2006-12-19 13:12 常言笑 閱讀(394) 評論(0) 編輯 收藏 所屬分類: JAVA/J2EE