一AOP編程概覽 面向對象編程技術進入軟件開發的主流對軟件的開發方式產生了極大的影響
開發者可以用一組實體以及這些實體之間的關系將系統形象地表示出來
這使得他們能夠設計出規模更大
更復雜的系統
開發周期也比以前更短
OO開發的唯一問題是
它本質上是靜態的
需求的細微變化就可能對開發進度造成重大影響
Aspect
Oriented Programming(AOP)是對OO技術的補充和完善
它允許開發者動態地修改靜態的OO模型
構造出一個能夠不斷增長以滿足新增需求的系統
就象現實世界中的對象會在其生命周期中不斷改變自身
應用程序也可以在發展中擁有新的功能
例如
許多人想必有過在開發簡單的Web應用時將Servlet作為入口點的經驗
即用Servlet接收HTML表單的輸入
經過處理後返回給用戶
開始時的Servlet可能是非常簡單的
只有剛好滿足用戶需求的最少量的代碼
然而
隨著
第二需求
的實現
例如實現異常處理
安全
日志等功能
代碼的體積就會增加到原來的三
四倍——之所以稱之為
第二需求
是因為Servlet的基本功能是接受和處理用戶的請求
對於這個目標來說
日志
安全之類的機制並不是必不可少的
AOP允許動態地改變OO的靜態模型
不必修改原來的靜態模型也可以加入滿足第二需求所需的代碼(實際上
甚至連原來的源代碼也不需要)
更令人稱奇的是
後來加入的代碼往往可以集中在一個地方
而不必象單純使用OO時那樣將後來加入的代碼分散到整個模型
二基本術語 在介紹AOP開發實例之前
我們先來了解幾個標准的AOP術語
以便更好地掌握相關的概念
█ Cross
cutting concern
在OO模型中
雖然大部份的類只有單一的
特定的功能
但它們通常會與其他類有著共同的第二需求
例如
當線程進入或離開某個方法時
我們可能既要在數據訪問層的類中記錄日志
又要在UI層的類中記錄日志
雖然每個類的基本功能極然不同
但用來滿足第二需求的代碼卻基本相同
█ Advice
它是指想要應用到現有模型的附加代碼
在本例中
它是指線程進入或退出某個方法時要運行的日志代碼
█ Point
cut
這個術語是指應用程序中的一個執行點
在這個執行點上需要采用前面的cross
cutting concern
在本例中
當線程進入一個方法時出現一個Point
cut
當線程離開方法時又出現另一個Point
cut
█ Aspect
Point
cut和advice結合在一起就叫做aspect
在下面的例子中
我們通過定義一個point
cut並給予適當的advice加入了一個日志(logging)aspect
AOP還有其它許多特性和術語
例如引入(Introduction)
即把接口/方法/域引入到現有的類——它極大地拓寬了開發者的想象力
不過本文只介紹一些最基本的持性
熟悉這裡介紹的概念後
你再深入一步研究AOP的其它特性
看看如何在自己的開發環境中使用它們
三現有的框架 目前最成熟
功能最豐富的AOP框架當數AspectJ
AspectJ已成為大多數其它框架跟從的標准
但是
AspectJ也走出了非同尋常的一步
它的實現為Java語言增添了新的關鍵詞
雖然新的語法並不難學
但卻意味著我們必須換一個編譯器
還要重新配制編輯器
只有這樣才能適應新的語法
在規模較大的開發組中
這些要求可能難以辦到
因為整個開發小組都會受到影響
由於語言本身的變化
開發小組把AOP技術引入到現有項目的學習周期隨之延長
現在我們需要的是這樣一個框架
它可以方便地引入
且不會對原來的開發和構造過程產生任何影響
滿足這些要求的框架不止一個
例如JBoss AOP
Nanning
Aspectwerkz(AW)
本文選用的是Aspectwerkz
因為它可能是最容易學習的框架
也是最容易集成到現有項目的框架
Aspectwerkz由Jonas Boner和Alexandre Vasseur創建
它是目前最快速
功能最豐富的框架之一
雖然它還缺乏AspectJ的某些功能
但己足以滿足大多數開發者在許多情形下的需要
Aspectwerkz最令人感興趣的特性之一是它能夠以兩種不同的模式運行
聯機模式和脫機模式
在聯機模式下
AW直接干預屬於JVM的底層類裝入機制
截取所有的類裝入請求
對字節碼實施即時轉換
AW提供了干預類裝入過程的許多選項
另外還有一個替代bin/java命令的封裝腳本
這個腳本能夠根據Java版本和JVM能力自動生成一組可運行的配制
對於開發者
聯機模式有許多優點
它能插入到任何類裝入器並在類裝入期間生成新的類
也就是說
我們不必手工修改應用程序的類
只要按通常的方式部署即可
不過
聯機模式要求對應用服務器進行額外的配制
有時這一要求可能很難滿足
在脫機模式下
生成類需要二個步驟
第一步是用標准的編譯器編譯
第二步是重點——以脫機模式運行AWcompiler編譯器
讓它處理新生成的類
編譯器將修改這些類的字節碼
根據一個XML文件的定義
在適當的point
cut插入advice
脫機模式的優點是AWcompiler生成的類能夠在任何JVM
以上的虛擬機運行
本文下面要用的就是這種模式
因為它不需要對Tomcat作任何修改
只要對構造過程稍作修改就可以照搬到大多數現有的項目
四安裝 本文將以一個簡單的Web應用程序為例
它用Ant編譯
部署在Tomcat
+ Servlet容器上
下面我們假定讀者己准備好上述環境
包括JVM
+
同時Tomcat被設置成從webapps文件夾自動部署應用
自動將WAR擴展到目錄(這是Tomcat默認的操作方式
因此只要你尚未修改Tomcat的運行方式
下面的范例可直接運行)
我們將把Tomcat的安裝位置稱為%TOMCAT_HOME%
⑴ 從下載Aspectwerkz
解開壓縮到適當的位置
我們將把這個位置稱為%ASPECTWERKZ_HOME%
⑵ 設置%ASPECTWERKZ_HOME%環境變量
⑶ 將Aspectwerkz加入到PATH環境變量
即設置set PATH=%PATH%;%ASPECTWERKZ_HOME%\bin\aspectwerkz
⑷ 下載本文的示范程序
將它放入%TOMCAT_HOME%\webapps文件夾
⑸ 將Aspectwerkz的運行時類加入到Tomcat的classpath
你可以將它的JAR文件放入示例應用的WEB
INF\lib文件夾
或放入%TOMCAT_HOME%\common\lib
五編譯示例應用 如果你想深入研究一下本文的示例應用
可以解開WAR文件提取它的內容
你會發現根目錄下有一個aspectwerkz
xml文件
構造應用時它會被復制到WEB
INF/classes目錄
Servlet和advice的源文件在WEB
INF/src目錄下
另外還有一個構建這些類的ANT腳本
在運行這個示例程序之前
你還要對它進行後期編譯
下面是具體的操作步驟
⑴ 在命令行窗口中
轉到解開WAR文件的目錄
⑵ 輸入下面的命令調用AW編譯器:aspectwerkz
offline aspectwerkz
xml WEB
INF/classes
cp %TOMCAT_HOME%\common\lib\servlet
jar
如後期編譯順利通過
應看到下面的輸出
(
s )
SUCCESS: WEB
INF\classes
在構建文件中有一個名稱為war的ANT任務
你可以用它重新創建WAR文件
六運行示例應用 首先啟動(或重新啟動)Tomcat
然後在浏覽器中打//localhost:
/demo/
頁面打開後
可以看到一個帶二個輸入框的HTML表單
一個輸入名字
一個輸入郵件地址
輸入一些數據
然後點擊按鈕提交表單
出現一個頁面顯示出聯系人信息和一個指向聯系人清單的鏈接
七代碼分析 JSP頁面就不分析了
現在我們對它不感興趣
我們來看看AOPServlet的代碼
package example;
import java
io
*;
import javax
servlet
*;
import javax
servlet
http
*;
public class AOPServlet extends HttpServlet {
public void doGet(HttpServletRequest request
HttpServletResponse response)
throws ServletException
IOException {
Person person = new Person();
if (request
getParameter(
name
) != null) {
person
setName(
request
getParameter(
name
));
}
if (request
getParameter(
email
) != null) {
person
setEmail(
request
getParameter(
email
));
}
request
setAttribute(
person
person);
RequestDispatcher rd =request
getRequestDispatcher(
/view
jsp
);
rd
forward(request
response);
}
}
在這個例子中
Servlet的代碼己盡量精簡
只包含一些必不可少的代碼
如創建了一個綁定請求參數的對象等
但沒有持久化操作
不需要額外的imports
它只實現了作為Servlet必須實現的最基本的操作
然而
根據說明文檔的要求
這個應用程序必須將所有Person類型的對象特久化
所以要為這個應用程序加入一個aspect
為創建這個aspect
我們首先要創建一個aspectwerkz
xml文件並將該文件放入classpath指定的目錄
本文示例提供了一個簡單的例子
你可以用編輯器打開查看
aspectwerkz
xml的第一部份定義了可用的advice
我們可以根據需要加入任意數量的advice
<advice
def name=
persist
class=
example
PersistenceAdvice
deployment
model=
perJVM
/>
在這個片段中
我們定義了一個名稱為persist的advice
它的類型是example
PersistenceAdvice
最後一個屬性定義了該advice的排它性
在這裡它的值是perJVM
From:http://tw.wingwit.com/Article/program/Java/hx/201311/26585.html