• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            Shuffy

            不斷的學(xué)習(xí),不斷的思考,才能不斷的進(jìn)步.Let's do better together!
            posts - 102, comments - 43, trackbacks - 0, articles - 19

            面向切面編程

            Posted on 2011-10-18 00:16 Shuffy 閱讀(1421) 評論(0)  編輯 收藏 引用 所屬分類: Java
                概述  

                  Aspect Oriented Programming(AOP),面向切面編程,是一個(gè)比較熱門的話題。AOP主要實(shí)現(xiàn)的目的是針對業(yè)務(wù)處理過程中的切面進(jìn)行提取,它所面對的是處理過程中的某個(gè)步驟或階段,以獲得邏輯過程中各部分之間低耦合性的隔離效果。比如我們最常見的就是日志記錄了,舉個(gè)例子,我們現(xiàn)在提供一個(gè)服務(wù)查詢學(xué)生信息的,但是我們希望記錄有誰進(jìn)行了這個(gè)查詢。如果按照傳統(tǒng)的OOP的實(shí)現(xiàn)的話,那我們實(shí)現(xiàn)了一個(gè)查詢學(xué)生信息的服務(wù)接口(StudentInfoService)和其實(shí)現(xiàn)類(StudentInfoServiceImpl.java),同時(shí)為了要進(jìn)行記錄的話,那我們在實(shí)現(xiàn)類(StudentInfoServiceImpl.java)中要添加其實(shí)現(xiàn)記錄的過程。這樣的話,假如我們要實(shí)現(xiàn)的服務(wù)有多個(gè)呢?那就要在每個(gè)實(shí)現(xiàn)的類都添加這些記錄過程。這樣做的話就會有點(diǎn)繁瑣,而且每個(gè)實(shí)現(xiàn)類都與記錄服務(wù)日志的行為緊耦合,違反了面向?qū)ο蟮囊?guī)則。那么怎樣才能把記錄服務(wù)的行為與業(yè)務(wù)處理過程中分離出來呢?看起來好像就是查詢學(xué)生的服務(wù)自己在進(jìn)行,但是背后日志記錄對這些行為進(jìn)行記錄,但是查詢學(xué)生的服務(wù)不知道存在這些記錄過程,這就是我們要討論AOP的目的所在。AOP的編程,好像就是把我們在某個(gè)方面的功能提出來與一批對象進(jìn)行隔離,這樣與一批對象之間降低了耦合性,可以就某個(gè)功能進(jìn)行編程。

                代碼分析

              我們直接從代碼入手吧,要實(shí)現(xiàn)以上的目標(biāo),我們可以使用一個(gè)動態(tài)代理類(Proxy),通過攔截一個(gè)對象的行為并添加我們需要的功能來完成。Java中的java.lang.reflect.Proxy類和java.lang.reflect.InvocationHandler接口為我們實(shí)現(xiàn)動態(tài)代理類提供了一個(gè)方案,但是該方案針對的對象要實(shí)現(xiàn)某些接口;如果針對的目的是類的話,cglib為我們提供了另外一個(gè)實(shí)現(xiàn)方案。等下會說明兩者的區(qū)別。

                 一、接口的實(shí)現(xiàn)方案:

              1)首先編寫我們的業(yè)務(wù)接口(StudentInfoService.java):
              public interface StudentInfoService{
              void findInfo(String studentName);
              }
              及其實(shí)現(xiàn)類(StudentInfoServiceImpl.java):
              public class StudentInfoServiceImpl implements StudentInfoService{
              public void findInfo(String name){
              System.out.println("你目前輸入的名字是:"+name);
              }
              }
              2)現(xiàn)在我們需要一個(gè)日志功能,在findInfo行為之前執(zhí)行并記錄其行為,那么我們就首先要攔截該行為。在實(shí)際執(zhí)行的過程中用一個(gè)代理類來替我們完成。Java中為我們提供了實(shí)現(xiàn)動態(tài)代理類的方案:
              1'處理攔截目的的類(MyHandler.java)
              import org.apache.log4j.Logger;
              import java.lang.reflect.InvocationHandler;
              import java.lang.reflect.Proxy;
              import java.lang.reflect.Method;
              public class MyHandler implements InvocationHandler{
              private Object proxyObj;
              private static Logger log=Logger.getLogger(MyHandler.class);
              public Object bind(Object obj){
              this.proxyObj=obj;
              return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),this);
              }
              public Object invoke(Object proxy,Method method,Object[] args) throws Throwable{
              Object result=null;
              try{
              //請?jiān)谶@里插入代碼,在方法前調(diào)用
              log.info("調(diào)用log日志方法"+method.getName());
              result=method.invoke(proxyObj,args); //原方法
              //請?jiān)谶@里插入代碼,方法后調(diào)用
              }catch(Exception e){
              e.printStackTrace();
              }
              return result;
              }
              }
              2'我們實(shí)現(xiàn)一個(gè)工廠,為了方便我們使用該攔截類(AOPFactory.java):
              public class AOPFactory{
              private static Object getClassInstance(String clzName){
              Object obj=null;
              try{
              Class cls=Class.forName(clzName);
              obj=(Object)cls.newInstance();
              }catch(ClassNotFoundException cnfe){
              System.out.println("ClassNotFoundException:"+cnfe.getMessage());
              }catch(Exception e){
              e.printStackTrace();
              }
              return obj;
              }
              public static Object getAOPProxyedObject(String clzName){
              Object proxy=null;
              MyHandler handler=new MyHandler();
              Object obj=getClassInstance(clzName);
              if(obj!=null) {
              proxy=handler.bind(obj);
              }else{
              System.out.println("Can't get the proxyobj");
              //throw
              }
              return proxy;
              }
              }
              3)基本的攔截與其工廠我們都實(shí)現(xiàn)了,現(xiàn)在測試(ClientTest.java):
              public class ClientTest{
              public static void main(String[] args){
              StudentInfoService studentInfo=(StudentInfoService)AOPFactory.getAOPProxyedObject("StudentInfoServiceImpl");
              studentInfo.findInfo("阿飛");
              }
              }
              輸出結(jié)果(看你的log4j設(shè)置):
              調(diào)用log日志方法findInfo
              你目前輸入的名字是:阿飛
              這樣我們需要的效果就出來了,業(yè)務(wù)處理自己在進(jìn)行,但是我們實(shí)現(xiàn)了日志功能,而業(yè)務(wù)處理(StudentInfoService)根本不知道存在該行為的。但是Java中提供的動態(tài)代理類的實(shí)現(xiàn)是針對實(shí)現(xiàn)了某些接口的類,如果沒有實(shí)現(xiàn)接口的話,不能創(chuàng)建代理類,看以上部分:
              return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),this);
              看到了沒有?obj.getClass().getInterfaces()要求實(shí)現(xiàn)了某些接口。以下提供哪些沒有實(shí)現(xiàn)接口的實(shí)現(xiàn)方案:

                 二、子類的實(shí)現(xiàn)方案。

              首先,請上網(wǎng)下CGLib的包,http://sourceforge.net/project/showfiles.php?group_id=56933 。設(shè)置好classpath路徑,CGLib與java標(biāo)準(zhǔn)庫提供的實(shí)現(xiàn)方案不同,cglib主要是基于實(shí)現(xiàn)類(如StudentInfoServiceImpl.java)擴(kuò)展一個(gè)子類來實(shí)現(xiàn)。與Dynamic Proxy中的Proxy和InvocationHandler相對應(yīng),net.sf.cglib.proxy.Enhancer和MethodInterceptor在CGLib中負(fù)責(zé)完成代理對象創(chuàng)建和方法截獲處理,產(chǎn)生的是目標(biāo)類的子類而不是通過接口來實(shí)現(xiàn)方法攔截的,Enhancer主要是用于構(gòu)造動態(tài)代理子類來實(shí)現(xiàn)攔截,MethodInterceptor(擴(kuò)展了Callback接口)主要用于實(shí)現(xiàn)around advice(AOP中的概念):
              1)我們的業(yè)務(wù)處理(StudentInfoServiceImpl.java):
              public class StudentInfoServiceImpl{
              public void findInfo(String name){
              System.out.println("你目前輸入的名字是:"+name);
              }
              }
              2)實(shí)行一個(gè)工具來處理日志功能(AOPInstrumenter.java):
              import net.sf.cglib.proxy.MethodInterceptor;
              import net.sf.cglib.proxy.Enhancer;
              import net.sf.cglib.proxy.MethodProxy;
              import java.lang.reflect.Method;
              import org.apache.log4j.Logger;
              public class AOPInstrumenter implements MethodInterceptor{
              private Logger log=Logger.getLogger(AOPInstrumenter.class);
              private Enhancer enhancer=new Enhancer();
              public Object getInstrumentedClass(Class clz){
              enhancer.setSuperclass(clz);
              enhancer.setCallback(this);
              return enhancer.create();
              }
              public Object intercept(Object o,Method method,Object[] args,MethodProxy proxy) throws Throwable{
              log.info("調(diào)用日志方法"+method.getName());
              Object result=proxy.invokeSuper(o,args);
              return result;
              }
              }
              3)我們來測試一下(AOPTest.java):
              public class AOPTest{
              public static void main(String[] args){
              AOPInstrumenter instrumenter=new AOPInstrumenter();
              StudentInfoServiceImpl studentInfo=(StudentInfoServiceImpl)instrumenter.getInstrumentedClass(StudentInfoServiceImpl.class);
              studentInfo.findInfo("阿飛");
              }
              }
              輸出結(jié)果與以上相同。
              CGLib中為實(shí)現(xiàn)以上目的,主要提供的類
              1)Enhancer:setCallback(Callback) ,setSuperclass(Class) ,create()返回動態(tài)子類Object
              2)MethodInterceptor必須實(shí)現(xiàn)的接口:intercept(Object,Method,Object[],MethodProxy)返回的是原方法調(diào)用的結(jié)果。和Proxy原理一樣。

                 三、AOP的基本概念:

              1)aspect(切面):實(shí)現(xiàn)了cross-cutting功能,是針對切面的模塊。最常見的是logging模塊,這樣,程序按功能被分為好幾層,如果按傳統(tǒng)的繼承的話,商業(yè)模型繼承日志模塊的話根本沒有什么意義,而通過創(chuàng)建一個(gè)logging切面就可以使用AOP來實(shí)現(xiàn)相同的功能了。
              2)jointpoint(連接點(diǎn),又叫插入點(diǎn)):連接點(diǎn)是切面插入應(yīng)用程序的地方,該點(diǎn)能被方法調(diào)用,而且也會被拋出意外。連接點(diǎn)是應(yīng)用程序提供給切面插入的地方,可以添加新的方法。比如以上我們的切點(diǎn)可以認(rèn)為是findInfo(String)方法。
              3)advice(通知,即附加行為):advice是我們切面功能的實(shí)現(xiàn),它通知程序新的行為。如在logging里,logging advice包括logging的實(shí)現(xiàn)代碼,比如像寫日志到一個(gè)文件中。advice在jointpoint處插入到應(yīng)用程序中。以上我們在MyHandler.java中實(shí)現(xiàn)了advice的功能
              4)pointcut(切入點(diǎn)):pointcut可以控制你把哪些advice應(yīng)用于jointpoint上去,通常你使用pointcuts通過正則表達(dá)式來把明顯的名字和模式進(jìn)行匹配應(yīng)用。決定了那個(gè)jointpoint會獲得通知。
              5)introduction:允許添加新的方法和屬性到類中。
              6)target(目標(biāo)類):是指那些將使用advice的類,一般是指獨(dú)立的那些商務(wù)模型。比如以上的StudentInfoServiceImpl.
              7)  proxy(代理類):使用了proxy的模式。是指應(yīng)用了advice的對象,看起來和target對象很相似。
              8)weaving(插入):是指應(yīng)用aspects到一個(gè)target對象創(chuàng)建proxy對象的過程:complie time,classload time,runtime

            原文鏈接:http://baike.baidu.com/view/1865230.htm
            国产午夜精品理论片久久影视 | 久久99精品国产麻豆不卡| 久久午夜伦鲁片免费无码| 国产婷婷成人久久Av免费高清| 国内精品久久国产大陆| 四虎影视久久久免费| 久久成人国产精品| 日产久久强奸免费的看| 91精品国产综合久久久久久| 要久久爱在线免费观看| 久久九九青青国产精品| 东方aⅴ免费观看久久av| 93精91精品国产综合久久香蕉| 亚洲中文久久精品无码ww16| 久久综合久久综合久久| 久久久久久午夜成人影院| 久久免费视频6| 99热成人精品免费久久| 99精品国产99久久久久久97| 久久国产视频99电影| 欧美777精品久久久久网| 亚洲精品乱码久久久久久久久久久久 | 国内精品久久久久影院优| 伊人久久大香线蕉成人| 久久免费精品一区二区| 久久精品一本到99热免费| 亚洲香蕉网久久综合影视| 久久人人爽人人爽人人片AV麻烦| 欧美国产精品久久高清| 国内精品久久久久久中文字幕| 久久综合久久综合久久| 久久国产精品-久久精品| 久久99精品久久久久久动态图| 麻豆成人久久精品二区三区免费 | 99久久精品国产免看国产一区| 人妻无码αv中文字幕久久琪琪布| 久久久久久亚洲精品影院| 久久久久久久综合狠狠综合| 国产一区二区久久久| 久久天天躁狠狠躁夜夜躁2014| 97视频久久久|