2015第29周二AOP
1、問題:想要添加日志記錄、性能監(jiān)控、安全監(jiān)測
2、最初解決方案
2.1、最初解決方案:在每個需要的類函數(shù)中重復(fù)寫上面處理代。
缺點(diǎn):太多重復(fù)代碼,且緊耦合
2.2、抽象類進(jìn)行共性設(shè)計,子類進(jìn)行個性設(shè)計,此處不講解,缺點(diǎn)一榮俱榮,一損俱損
2.3、使用裝飾器模式/代理模式改進(jìn)的解決方案
裝飾器模式:動態(tài)地給一個對象添加一些額外的職責(zé)。就增加功能來說, 裝飾器模式相比生成子類更為靈活。
代理模式:為其他對象提供一種代理以控制對這個對象的訪問。
缺點(diǎn):緊耦合,每個業(yè)務(wù)邏輯需要一個裝飾器實(shí)現(xiàn)或代理
2.4、JDK動態(tài)代理解決方案(比較通用的解決方案)
Java代碼??
1.? public?class?MyInvocationHandler?implements?InvocationHandler {
2.? private?Object target;
3.? public?MyInvocationHandler(Object target) {
4.? this.target = target;
5.? }
6.? @Override
7.? public?Object invoke(Object proxy, Method method, Object[] args)?throws?Throwable {
8.? //1.記錄日志 2.時間統(tǒng)計開始 3.安全檢查
9.? Object retVal = method.invoke(target, args);
10. //4.時間統(tǒng)計結(jié)束
11. return?retVal;
12. }
13. public?static?Object proxy(Object target) {
14. return?Proxy.newProxyInstance(target.getClass().getClassLoader(),
15. target.getClass().getInterfaces(),?new?MyInvocationHandler(target));
16. }
17. }
編程模型
Java代碼??
1.? //proxy 在其上調(diào)用方法的代理實(shí)例
2.? //method 攔截的方法
3.? //args 攔截的參數(shù)
4.? Override
5.? public?Object invoke(Object proxy, Method method, Object[] args)?throws?Throwable {
6.? Object retVal=null;
7.? //預(yù)處理
8.? //前置條件判斷
9.? boolean?ok =?true;
10. if(!ok) {//不滿足條件
11. throw?new?RuntimeException("你沒有權(quán)限");
12. }
13. else?{//反射調(diào)用目標(biāo)對象的某個方法
14. retVal = method.invoke(target, args);
15. }
16. //后處理
17. return?retVal;
18. }
19.
?
缺點(diǎn):使用麻煩,不能代理類,只能代理接口
CGLIB動態(tài)代理解決方案(比較通用的解決方案)
Java代碼??
1.? public?class?MyInterceptor?implements?MethodInterceptor {
2.? private?Object target;
3.? public?MyInterceptor(Object target) {
4.? this.target = target;
5.? }
6.? @Override
7.? public?Object intercept(Object proxy, Method method, Object[] args,
8.? MethodProxy invocation)?throws?Throwable {
9.? //1.記錄日志 2.時間統(tǒng)計開始 3.安全檢查
10. Object retVal = invocation.invoke(target, args);
11. //4.時間統(tǒng)計結(jié)束
12. return?retVal;
13. }
14. public?static?Object proxy(Object target) {
15. return?Enhancer.create(target.getClass(),?new?MyInterceptor(target));
16. }
17. }
編程模型
Java代碼??
1.? //proxy 在其上調(diào)用方法的代理實(shí)例 method攔截的方法 args 攔截的參數(shù)
2.? //invocation 用來去調(diào)用被代理對象方法的
3.? @Override
4.? public?Object intercept(Object proxy, Method method, Object[] args,
5.? MethodProxy invocation)?throws?Throwable {
6.? //預(yù)處理
7.? //前置條件判斷
8.? boolean?ok =?true;
9.? if(!ok) {//不滿足條件
10. throw?new?RuntimeException("出錯了");
11. }
12. else?{//調(diào)用目標(biāo)對象的某個方法
13. Object retVal = invocation.invoke(target, args);
14. }
15. //后處理
16. return?retVal;
17. }
優(yōu)點(diǎn):能代理接口和類
缺點(diǎn):使用麻煩,不能代理final類
動態(tài)代理本質(zhì)
本質(zhì):對目標(biāo)對象增強(qiáng)
最終表現(xiàn)為類(動態(tài)創(chuàng)建子類),看手工生成(子類)還是自動生成(子類)
代理限制:
只能在父類方法被調(diào)用之前或之后進(jìn)行增強(qiáng)(功能的修改),不能在中間進(jìn)行修改,要想在方法調(diào)用中增強(qiáng),需要ASM(java?字節(jié)碼生成庫)
其他動態(tài)代理框架
jboss:javassist?(hibernate 3.3中默認(rèn)為javassist)
(hibernate 3.3之前中默認(rèn)為cglib)
2.5、AOP解決方案(通用且簡單的解決方案)
Java代碼??
1.? @Aspect
2.? public?class?PayEbiAspect {
3.? @Pointcut(value="execution(* pay(..))")
4.? public?void?pointcut() {}
5.? @Around(value="pointcut()")
6.? public?Object around(ProceedingJoinPoint pjp)?throws?Throwable {
7.? //1.記錄日志
8.? //2.時間統(tǒng)計開始
9.? //3.安全檢查
10. Object retVal = pjp.proceed();//調(diào)用目標(biāo)對象的真正方法
11. //4.時間統(tǒng)計結(jié)束
12. return?retVal;
13. }
14. }
編程模型
Java代碼??
1.? //2 切入點(diǎn)
2.? @Pointcut(value="execution(* *(..))")
3.? public?void?pointcut() {}
4.? //3 攔截器的interceptor
5.? @Around(value="pointcut()")
6.? public?Object around(ProceedingJoinPoint pjp)?throws?Throwable {
7.? Object retVal=null;
8.? //預(yù)處理
9.? //前置條件判斷
10. boolean?ok =?true;
11. if(!ok) {//不滿足條件
12. throw?new?RuntimeException("你沒有權(quán)限");
13. }
14. else?{//調(diào)用目標(biāo)對象的某個方法
15. retVal = pjp.proceed();
16. }
17. //后處理
18. return?retVal;
19. }
缺點(diǎn):依賴AOP框架
AOP入門
概念:
n關(guān)注點(diǎn):可以認(rèn)為是所關(guān)注的任何東西,比如上邊的支付組件;
n關(guān)注點(diǎn)分離:將問題細(xì)化為單獨(dú)部分,即可以理解為不可再分割的組件,如上邊的日志組件和支付組件;
n橫切關(guān)注點(diǎn):會在多個模塊中出現(xiàn),使用現(xiàn)有的編程方法,橫切關(guān)注點(diǎn)會橫越多個模塊,結(jié)果是使系統(tǒng)難以設(shè)計、理解、實(shí)現(xiàn)和演進(jìn),如日志組件橫切于支付組件。
織入:橫切關(guān)注點(diǎn)分離后,需要通過某種技術(shù)將橫切關(guān)注點(diǎn)融合到系統(tǒng)中從而完成需要的功能,因此需要織入,織入可能在編譯期、加載期、運(yùn)行期等進(jìn)行。
nAOP是什么(Aspect Oriented Programming)
AOP是一種編程范式,提供從另一個角度來考慮程序結(jié)構(gòu)以完善面向?qū)ο缶幊?#xff08;OOP)。
AOP為開發(fā)者提供了一種描述橫切關(guān)注點(diǎn)的機(jī)制,并能夠自動將橫切關(guān)注點(diǎn)織入到面向?qū)ο蟮能浖到y(tǒng)中,從而實(shí)現(xiàn)了橫切關(guān)注點(diǎn)的模塊化。
AOP能夠?qū)⒛切┡c業(yè)務(wù)無關(guān),卻為業(yè)務(wù)模塊所共同調(diào)用的邏輯或責(zé)任,例如事務(wù)處理、日志管理、權(quán)限控制等,封裝起來,便于減少系統(tǒng)的重復(fù)代碼,降低模塊間的耦合度,并有利于未來的可操作性和可維護(hù)性。
nAOP能干什么,也是AOP帶來的好處
1:降低模塊的耦合度
2:使系統(tǒng)容易擴(kuò)展
3:設(shè)計決定的遲綁定:使用AOP,設(shè)計師可以推遲為將來的需求作決定,因?yàn)樗?/span>
可以把這種需求作為獨(dú)立的方面很容易的實(shí)現(xiàn)。
4:更好的代碼復(fù)用性
AOP基本概念
連接點(diǎn)(Joinpoint):
表示需要在程序中插入橫切關(guān)注點(diǎn)的擴(kuò)展點(diǎn),連接點(diǎn)可能是類初始化、方法執(zhí)行、方法調(diào)用、字段調(diào)用或處理異常等等,Spring只支持方法執(zhí)行連接點(diǎn),在AOP中表示為“在哪里做”;
切入點(diǎn)(Pointcut):
選擇一組相關(guān)連接點(diǎn)的模式,即可以認(rèn)為連接點(diǎn)的集合,Spring支持perl5正則表達(dá)式和AspectJ切入點(diǎn)模式,Spring默認(rèn)使用AspectJ語法,在AOP中表示為“在哪里做的集合”;
增強(qiáng)(Advice):或稱為增強(qiáng)
在連接點(diǎn)上執(zhí)行的行為,增強(qiáng)提供了在AOP中需要在切入點(diǎn)所選擇的連接點(diǎn)處進(jìn)行擴(kuò)展現(xiàn)有行為的手段;包括前置增強(qiáng)(before advice)、后置增強(qiáng) (after advice)、環(huán)繞增強(qiáng) (around advice),在Spring中通過代理模式實(shí)現(xiàn)AOP,并通過攔截器模式以環(huán)繞連接點(diǎn)的攔截器鏈織入增強(qiáng) ;在AOP中表示為“做什么”;
方面/切面(Aspect):
橫切關(guān)注點(diǎn)的模塊化,比如上邊提到的日志組件。可以認(rèn)為是增強(qiáng)、引入和切入點(diǎn)的組合;在Spring中可以使用Schema和@AspectJ方式進(jìn)行組織實(shí)現(xiàn);在AOP中表示為“在哪里做和做什么集合”;
目標(biāo)對象(Target Object):
需要被織入橫切關(guān)注點(diǎn)的對象,即該對象是切入點(diǎn)選擇的對象,需要被增強(qiáng)的對象,從而也可稱為“被增強(qiáng)對象”;由于Spring AOP?通過代理模式實(shí)現(xiàn),從而這個對象永遠(yuǎn)是被代理對象,在AOP中表示為“對誰做”;
AOP代理(AOP Proxy):
AOP框架使用代理模式創(chuàng)建的對象,從而實(shí)現(xiàn)在連接點(diǎn)處插入增強(qiáng)(即應(yīng)用切面),就是通過代理來對目標(biāo)對象應(yīng)用切面。在Spring中,AOP代理可以用JDK動態(tài)代理或CGLIB代理實(shí)現(xiàn),而通過攔截器模型應(yīng)用切面。
織入(Weaving):
織入是一個過程,是將切面應(yīng)用到目標(biāo)對象從而創(chuàng)建出AOP代理對象的過程,織入可以在編譯期、類裝載期、運(yùn)行期進(jìn)行。
引入(inter-type declaration):
也稱為內(nèi)部類型聲明,為已有的類添加額外新的字段或方法,Spring允許引入新的接口(必須對應(yīng)一個實(shí)現(xiàn))到所有被代理對象(目標(biāo)對象),?在AOP中表示為“做什么(新增什么)”;
AOP的Advice類型
前置增強(qiáng)(Before advice):
在某連接點(diǎn)之前執(zhí)行的增強(qiáng),但這個增強(qiáng)不能阻止連接點(diǎn)前的執(zhí)行(除非它拋出一個異常)。
后置返回增強(qiáng)(After returning advice):
在某連接點(diǎn)正常完成后執(zhí)行的增強(qiáng):例如,一個方法沒有拋出任何異常,正常返回。
后置異常增強(qiáng)(After throwing advice):
在方法拋出異常退出時執(zhí)行的增強(qiáng)。
后置最終增強(qiáng)(After (finally) advice):
當(dāng)某連接點(diǎn)退出的時候執(zhí)行的增強(qiáng)(不論是正常返回還是異常退出)。
環(huán)繞增強(qiáng)(Around Advice):
包圍一個連接點(diǎn)的增強(qiáng),如方法調(diào)用。這是最強(qiáng)大的一種增強(qiáng)類型。 環(huán)繞增強(qiáng)可以在方法調(diào)用前后完成自定義的行為。它也會選擇是否繼續(xù)執(zhí)行連接點(diǎn)或直接返回它們自己的返回值或拋出異常來結(jié)束執(zhí)行。
橫切關(guān)注點(diǎn)的表現(xiàn)有:
·代碼糾結(jié)/混亂——當(dāng)一個模塊或代碼段同時管理多個關(guān)注點(diǎn)時發(fā)生這種情況。如我既要實(shí)現(xiàn)業(yè)務(wù)、還要實(shí)現(xiàn)安全和事務(wù)。即有些關(guān)注點(diǎn)同時被多個不同的模塊實(shí)現(xiàn)。實(shí)現(xiàn)了重復(fù)的功能。
·代碼分散——當(dāng)一個關(guān)注點(diǎn)分布在許多模塊中并且未能很好地局部化和模塊化時發(fā)生這種情況 。如許多模塊調(diào)用用戶是否登錄驗(yàn)證代碼。調(diào)用了重復(fù)的功能。
AOP包括三個清晰的開發(fā)步驟:
1:功能橫切:找出橫切關(guān)注點(diǎn)。
2:實(shí)現(xiàn)分離:各自獨(dú)立的實(shí)現(xiàn)這些橫切關(guān)注點(diǎn)所需要完成的功能。
3:功能回貼:在這一步里,方面集成器通過創(chuàng)建一個模塊單元——?方面來指定重組的規(guī)則。重組過程——也叫織入或結(jié)合——?則使用這些信息來構(gòu)建最終系統(tǒng)。
?來源:http://jinnianshilongnian.iteye.com/blog/1474325
來自為知筆記(Wiz)
總結(jié)
以上是生活随笔為你收集整理的2015第29周二AOP的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Jquery Money 验证,转换成千
- 下一篇: 认识IL