AOP編程入門–Java篇

來源:互聯網
上載者:User
 Aspect Oriented Programming(AOP),面向切面編程,是一個比較熱門的話題。AOP主要實現的目的是針對業務處理過程中的切面進行提取,它所面對的是處理過程中的某個步驟或階段,以獲得邏輯過程中各部分之間低耦合性的隔離效果。比如我們最常見的就是日誌記錄了,舉個例子,我們現在提供一個服務查詢學生資訊的,但是我們希望記錄有誰進行了這個查詢。如果按照傳統的OOP的實現的話,那我們實現了一個查詢學生資訊的服務介面(StudentInfoService)和其實作類別(StudentInfoServiceImpl.java),同時為了要進行記錄的話,那我們在實作類別(StudentInfoServiceImpl.java)中要添加其實現記錄的過程。這樣的話,假如我們要實現的服務有多個呢?那就要在每個實現的類都添加這些記錄過程。這樣做的話就會有點繁瑣,而且每個實作類別都與記錄服務日誌的行為緊耦合,違反了物件導向的規則。那麼怎樣才能把記錄服務的行為與業務處理過程中分離出來呢?看起來好像就是查詢學生的服務自己在進行,但是背後日誌記錄對這些行為進行記錄,但是查詢學生的服務不知道存在這些記錄過程,這就是我們要討論AOP的目的所在。AOP的編程,好像就是把我們在某個方面的功能提出來與一批對象進行隔離,這樣與一批對象之間降低了耦合性,可以就某個功能進行編程。
    我們直接從代碼入手吧,要實現以上的目標,我們可以使用一個動態代理類(Proxy),通過攔截一個對象的行為並添加我們需要的功能來完成。Java中的java.lang.reflect.Proxy類和java.lang.reflect.InvocationHandler介面為我們實現動態代理類提供了一個方案,但是該方案針對的對象要實現某些介面;如果針對的目的是類的話,cglib為我們提供了另外一個實現方案。等下會說明兩者的區別。
一、介面的實現方案:
1)首先編寫我們的業務介面(StudentInfoService.java):
public interface StudentInfoService{
 void findInfo(String studentName);
}
     及其實作類別(StudentInfoServiceImpl.java):
public class StudentInfoServiceImpl implements StudentInfoService{
 public void findInfo(String name){
  System.out.println("你目前輸入的名字是:"+name);
 }
}
2)現在我們需要一個日誌功能,在findInfo行為之前執行並記錄其行為,那麼我們就首先要攔截該行為。在實際執行的過程中用一個代理類來替我們完成。Java中為我們提供了實現動態代理類的方案:

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{
   //請在這裡插入代碼,在方法前調用
   log.info("調用log日誌方法"+method.getName());
   result=method.invoke(proxyObj,args); //原方法
   //請在這裡插入代碼,方法後調用
  }catch(Exception e){
   e.printStackTrace();
  }
  return result;
 }
}
2'我們實現一個工廠,為了方便我們使用該攔截類(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)基本的攔截與其工廠我們都實現了,現在測試(ClientTest.java):
public class ClientTest{
 public static void main(String[] args){
  StudentInfoService studentInfo=(StudentInfoService)AOPFactory.getAOPProxyedObject("StudentInfoServiceImpl");
  studentInfo.findInfo("阿飛");
 }
}
輸出結果(看你的log4j設定):
[INFO]調用log日誌方法findInfo
你目前輸入的名字是:阿飛
     這樣我們需要的效果就出來了,業務處理自己在進行,但是我們實現了日誌功能,而業務處理(StudentInfoService)根本不知道存在該行為的。但是Java中提供的動態代理類的實現是針對實現了某些介面的類,如果沒有實現介面的話,不能建立代理類,看以上部分:
return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),this);
看到了沒有?obj.getClass().getInterfaces()要求實現了某些介面。以下提供哪些沒有實現介面的實現方案:

二、子類的實現方案。
      首先,請上網下CGLib的包,http://sourceforge.net/project/showfiles.php?group_id=56933 。設定好classpath路徑,CGLib與java標準庫提供的實現方案不同,cglib主要是基於實作類別(如StudentInfoServiceImpl.java)擴充一個子類來實現。與Dynamic Proxy中的Proxy和InvocationHandler相對應,net.sf.cglib.proxy.Enhancer和MethodInterceptor在CGLib中負責完成代理對象建立和方法截獲處理,產生的是目標類的子類而不是通過介面來實現方法攔截的,Enhancer主要是用於構造動態代理子類來實現攔截,MethodInterceptor(擴充了Callback介面)主要用於實現around advice(AOP中的概念):
     1)我們的業務處理(StudentInfoServiceImpl.java):
public class StudentInfoServiceImpl{
 public void findInfo(String name){
  System.out.println("你目前輸入的名字是:"+name);
 }
}
     2)實行一個工具來處理日誌功能(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("調用日誌方法"+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("阿飛");
 }
}
   輸出結果與以上相同。
 CGLib中為實現以上目的,主要提供的類
1)Enhancer:setCallback(Callback) ,setSuperclass(Class) ,create()返回動態子類Object
2)MethodInterceptor必須實現的介面:intercept(Object,Method,Object[],MethodProxy)返回的是原方法調用的結果。和Proxy原理一樣。

三、以上的兩個簡單實現AOP的方案都為你準備好了,你可以自己編寫測試一下,以下簡單介紹一下AOP的基本概念:
1)aspect(切面):實現了cross-cutting功能,是針對切面的模組。最常見的是logging模組,這樣,程式按功能被分為好幾層,如果按傳統的繼承的話,商業模型繼承日誌模組的話根本沒有什麼意義,而通過建立一個logging切面就可以使用AOP來實現相同的功能了。
2)jointpoint(連接點):連接點是切面插入應用程式的地方,該點能被方法調用,而且也會被拋出意外。連接點是應用程式提供給切面插入的地方,可以添加新的方法。比如以上我們的切點可以認為是findInfo(String)方法。
3)advice(處理邏輯):advice是我們切面功能的實現,它通知程式新的行為。如在logging裡,logging advice包括logging的實現代碼,比如像寫日誌到一個檔案中。advice在jointpoint處插入到應用程式中。以上我們在MyHandler.java中實現了advice的功能
4)pointcut(切點):pointcut可以控制你把哪些advice應用於jointpoint上去,通常你使用pointcuts通過Regex來把明顯的名字和模式進行匹配應用。決定了那個jointpoint會獲得通知。
5)introduction:允許添加新的方法和屬性到類中。
6)target(目標類):是指那些將使用advice的類,一般是指獨立的那些商務模型。比如以上的StudentInfoServiceImpl.

7)proxy(代理類):使用了proxy的模式。是指應用了advice的對象,看起來和target對象很相似。
8)weaving(插入):是指應用aspects到一個target對象建立proxy對象的過程:complie time,classload time,runtime

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.