Posted on 2012-04-15 16:37
zljpp 閱讀(136)
評論(0) 編輯 收藏
1、問題?

問題:想要添加日志記錄、性能監(jiān)控、安全監(jiān)測?
?
2、最初解決方案?
2.1、最初解決方案

缺點:太多重復代碼,且緊耦合
?
2.2、抽象類進行共性設計,子類進行個性設計,此處不講解,缺點一榮俱榮,一損俱損
?
2.3、使用裝飾器模式/代理模式改進的解決方案
裝飾器模式:動態(tài)地給一個對象添加一些額外的職責。就增加功能來說, 裝飾器模式相比生成子類更為靈活。
代理模式:為其他對象提供一種代理以控制對這個對象的訪問。

?
缺點:緊耦合,每個業(yè)務邏輯需要一個裝飾器實現(xiàn)或代理
2.4、JDK動態(tài)代理解決方案(比較通用的解決方案)?
public class MyInvocationHandler implements InvocationHandler {
private Object target;
public MyInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//1.記錄日志 2.時間統(tǒng)計開始 3.安全檢查
Object retVal = method.invoke(target, args);
//4.時間統(tǒng)計結束
return retVal;
}
public static Object proxy(Object target) {
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), new MyInvocationHandler(target));
}
}
?編程模型?
//proxy 在其上調用方法的代理實例
//method 攔截的方法
//args 攔截的參數(shù)
Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object retVal=null;
//預處理
//前置條件判斷
boolean ok = true;
if(!ok) {//不滿足條件
throw new RuntimeException("你沒有權限");
}
else {//反射調用目標對象的某個方法
retVal = method.invoke(target, args);
}
//后處理
return retVal;
}
?
缺點:使用麻煩,不能代理類,只能代理接口??
?
CGLIB動態(tài)代理解決方案(比較通用的解決方案)
public class MyInterceptor implements MethodInterceptor {
private Object target;
public MyInterceptor(Object target) {
this.target = target;
}
@Override
public Object intercept(Object proxy, Method method, Object[] args,
MethodProxy invocation) throws Throwable {
//1.記錄日志 2.時間統(tǒng)計開始 3.安全檢查
Object retVal = invocation.invoke(target, args);
//4.時間統(tǒng)計結束
return retVal;
}
public static Object proxy(Object target) {
return Enhancer.create(target.getClass(), new MyInterceptor(target));
}
}
?編程模型
//proxy 在其上調用方法的代理實例 method攔截的方法 args 攔截的參數(shù)
//invocation 用來去調用被代理對象方法的
@Override
public Object intercept(Object proxy, Method method, Object[] args,
MethodProxy invocation) throws Throwable {
//預處理
//前置條件判斷
boolean ok = true;
if(!ok) {//不滿足條件
throw new RuntimeException("出錯了");
}
else {//調用目標對象的某個方法
Object retVal = invocation.invoke(target, args);
}
//后處理
return retVal;
}
?
動態(tài)代理本質?
本質:對目標對象增強
???????????最終表現(xiàn)為類(動態(tài)創(chuàng)建子類),看手工生成(子類)還是自動生成(子類)
代理限制:
???????????只能在父類方法被調用之前或之后進行增強(功能的修改),不能在中間進行修改,要想在方法調用中增強,需要ASM(java?字節(jié)碼生成庫)
其他動態(tài)代理框架
jboss:javassist?(hibernate 3.3中默認為javassist)
???????????????????????????(hibernate 3.3之前中默認為cglib)

?

?
2.5、AOP解決方案(通用且簡單的解決方案)
@Aspect
public class PayEbiAspect {
@Pointcut(value="execution(* pay(..))")
public void pointcut() {}
@Around(value="pointcut()")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
//1.記錄日志
//2.時間統(tǒng)計開始
//3.安全檢查
Object retVal = pjp.proceed();//調用目標對象的真正方法
//4.時間統(tǒng)計結束
return retVal;
}
}
編程模型
//2 切入點
@Pointcut(value="execution(* *(..))")
public void pointcut() {}
//3 攔截器的interceptor
@Around(value="pointcut()")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
Object retVal=null;
//預處理
//前置條件判斷
boolean ok = true;
if(!ok) {//不滿足條件
throw new RuntimeException("你沒有權限");
}
else {//調用目標對象的某個方法
retVal = pjp.proceed();
}
//后處理
return retVal;
}
?
缺點:依賴AOP框架?
AOP入門
概念:
n關注點:可以認為是所關注的任何東西,比如上邊的支付組件;
n關注點分離:將問題細化為單獨部分,即可以理解為不可再分割的組件,如上邊的日志組件和支付組件;
n橫切關注點:會在多個模塊中出現(xiàn),使用現(xiàn)有的編程方法,橫切關注點會橫越多個模塊,結果是使系統(tǒng)難以設計、理解、實現(xiàn)和演進,如日志組件橫切于支付組件。
織入:橫切關注點分離后,需要通過某種技術將橫切關注點融合到系統(tǒng)中從而完成需要的功能,因此需要織入,織入可能在編譯期、加載期、運行期等進行。
nAOP是什么(Aspect?? Oriented?? Programming)
?AOP是一種編程范式,提供從另一個角度來考慮程序結構以完善面向對象編程(OOP)。
?AOP為開發(fā)者提供了一種描述橫切關注點的機制,并能夠自動將橫切關注點織入到面向對象的軟件系統(tǒng)中,從而實現(xiàn)了橫切關注點的模塊化。
?AOP能夠將那些與業(yè)務無關,卻為業(yè)務模塊所共同調用的邏輯或責任,例如事務處理、日志管理、權限控制等,封裝起來,便于減少系統(tǒng)的重復代碼,降低模塊間的耦合度,并有利于未來的可操作性和可維護性。
nAOP能干什么,也是AOP帶來的好處
1:降低模塊的耦合度
2:使系統(tǒng)容易擴展
3:設計決定的遲綁定:使用AOP,設計師可以推遲為將來的需求作決定,因為它
可以把這種需求作為獨立的方面很容易的實現(xiàn)。
4:更好的代碼復用性

?
AOP基本概念
?連接點(Joinpoint):
??? 表示需要在程序中插入橫切關注點的擴展點,連接點可能是類初始化、方法執(zhí)行、方法調用、字段調用或處理異常等等,Spring只支持方法執(zhí)行連接點,在AOP中表示為“在哪里做”;
切入點(Pointcut):
??? 選擇一組相關連接點的模式,即可以認為連接點的集合,Spring支持perl5正則表達式和AspectJ切入點模式,Spring默認使用AspectJ語法,在AOP中表示為“在哪里做的集合”;
增強(Advice):或稱為增強
??? 在連接點上執(zhí)行的行為,增強提供了在AOP中需要在切入點所選擇的連接點處進行擴展現(xiàn)有行為的手段;包括前置增強(before advice)、后置增強?(after advice)、環(huán)繞增強?(around advice),在Spring中通過代理模式實現(xiàn)AOP,并通過攔截器模式以環(huán)繞連接點的攔截器鏈織入增強?;在AOP中表示為“做什么”;
方面/切面(Aspect):
????? 橫切關注點的模塊化,比如上邊提到的日志組件。可以認為是增強、引入和切入點的組合;在Spring中可以使用Schema和@AspectJ方式進行組織實現(xiàn);在AOP中表示為“在哪里做和做什么集合”;
目標對象(Target Object):
??? 需要被織入橫切關注點的對象,即該對象是切入點選擇的對象,需要被增強的對象,從而也可稱為“被增強對象”;由于Spring AOP?通過代理模式實現(xiàn),從而這個對象永遠是被代理對象,在AOP中表示為“對誰做”;
AOP代理(AOP Proxy):
??? AOP框架使用代理模式創(chuàng)建的對象,從而實現(xiàn)在連接點處插入增強(即應用切面),就是通過代理來對目標對象應用切面。在Spring中,AOP代理可以用JDK動態(tài)代理或CGLIB代理實現(xiàn),而通過攔截器模型應用切面。
織入(Weaving):
??? 織入是一個過程,是將切面應用到目標對象從而創(chuàng)建出AOP代理對象的過程,織入可以在編譯期、類裝載期、運行期進行。
引入(inter-type declaration):
??? 也稱為內部類型聲明,為已有的類添加額外新的字段或方法,Spring允許引入新的接口(必須對應一個實現(xiàn))到所有被代理對象(目標對象),?在AOP中表示為“做什么(新增什么)”;
AOP的Advice類型
前置增強(Before advice):
??? 在某連接點之前執(zhí)行的增強,但這個增強不能阻止連接點前的執(zhí)行(除非它拋出一個異常)。
后置返回增強(After returning advice):
??? 在某連接點正常完成后執(zhí)行的增強:例如,一個方法沒有拋出任何異常,正常返回。
后置異常增強(After throwing advice):
??? 在方法拋出異常退出時執(zhí)行的增強。
后置最終增強(After (finally) advice):
??? 當某連接點退出的時候執(zhí)行的增強(不論是正常返回還是異常退出)。
環(huán)繞增強(Around Advice):
??? 包圍一個連接點的增強,如方法調用。這是最強大的一種增強類型。 環(huán)繞增強可以在方法調用前后完成自定義的行為。它也會選擇是否繼續(xù)執(zhí)行連接點或直接返回它們自己的返回值或拋出異常來結束執(zhí)行。

?
AOP開發(fā)步驟
? 類似于IoC/DI容器開發(fā)步驟,需要描述哪個連接點需要哪個通用功能(增強)
橫切關注點的表現(xiàn)有:
·代碼糾結/混亂——當一個模塊或代碼段同時管理多個關注點時發(fā)生這種情況。
·代碼分散——當一個關注點分布在許多模塊中并且未能很好地局部化和模塊化時發(fā)生這種情況 。
AOP包括三個清晰的開發(fā)步驟:
1:功能橫切:找出橫切關注點。
2:實現(xiàn)分離:各自獨立的實現(xiàn)這些橫切關注點所需要完成的功能。
3:功能回貼:在這一步里,方面集成器通過創(chuàng)建一個模塊單元——?方面來指定重組的規(guī)則。重組過程——也叫織入或結合——?則使用這些信息來構建最終系統(tǒng)。
推薦閱讀書籍:
AspectJ in Action
AOSD中文版--基于用例的面向方面軟件開發(fā)
推薦閱讀的帖子:
?
文章主要是為了拋磚引玉,希望有更多牛人的指點。
已有 0 人發(fā)表留言,猛擊->>這里<<-參與討論