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