1. 程式人生 > >Java 動態代理及AOP實現機制

Java 動態代理及AOP實現機制

www javadoc 底層 service ack 兩種方法 實現機制 之間 sets

AOP實現機制
http://www.iteye.com/topic/1116696

AOP: (Aspect Oriented Programming) 面向切面編程
AOP包括切面(aspect)、通知(advice)、連接點(joinpoint),實現方式就是通過對目標對象的代理在連接點前後加入通知,完成統一的切面操作

利用AOP可以對業務邏輯的各個部分進行隔離,從而使得業務邏輯各部分之間的耦合度降低,提高程序的可重用性,同時提高了開發的效率。主要的功能是:日誌記錄,性能統計,安全控制,事務處理,異常處理等等。

面向接口編程,(橫向編程)


AOP的底層實現-CGLIB動態代理和JDK動態代理

http://blog.csdn.net/dreamrealised/article/details/12885739

AOP是目前Spring框架中的核心之一,在應用中具有非常重要的作用,也是Spring其他組件的基礎。它是一種面向切面編程的思想。關於AOP的基礎知識,相信多數童鞋都已經了如指掌,我們就略過這部分,來講解下AOP的核心功能的底層實現機制:如何用動態代理來實現切面攔截。
AOP的攔截功能是由java中的動態代理來實現的。說白了,就是在目標類的基礎上增加切面邏輯,生成增強的目標類(該切面邏輯或者在目標類函數執行之前,或者目標類函數執行之後,或者在目標類函數拋出異常時候執行。不同的切入時機對應不同的Interceptor的種類,如BeforeAdviseInterceptor,AfterAdviseInterceptor以及ThrowsAdviseInterceptor等)。
那麽動態代理是如何實現將切面邏輯(advise)織入到目標類方法中去的呢?下面我們就來詳細介紹並實現AOP中用到的兩種動態代理。
AOP的源碼中用到了兩種動態代理來實現攔截切入功能:jdk動態代理和cglib動態代理。兩種方法同時存在

,各有優劣。

jdk動態代理是由java內部的反射機制來實現的,

cglib動態代理底層則是借助asm來實現的。

總的來說,反射機制在生成類的過程中比較高效,而asm在生成類之後的相關執行過程中比較高效(可以通過將asm生成的類進行緩存,這樣解決asm生成類過程低效問題)。還有一點必須註意:jdk動態代理的應用前提,必須是目標類基於統一的接口。如果沒有上述前提,jdk動態代理不能應用。由此可以看出,jdk動態代理有一定的局限性,cglib這種第三方類庫實現的動態代理應用更加廣泛,且在效率上更有優勢。
一、jdk動態代理實現AOP攔截(代碼中的關鍵地方都添加了註釋)

1、為目標類(target)定義統一的接口類Service,這個是jdk動態代理必須的前提。

package jdkproxy; 

/** 
* 該類是所有被代理類的接口類,jdk實現的代理要求被代理類基於統一的接口 
* 
*/ 
public interface Service { 
    /** 
    * add方法 
    */ 
    public void add(); 

    /** 
    * update方法 
    */ 
    public void update(); 
} 


2、目標類AService,我們的實驗目標就是在AService中add和update方法的前後實現攔截,加入自定義切面邏輯advise

package jdkproxy; 

/** 
* 被代理類,即目標類target 
* 
* 
*/ 
public class AService implements Service { 
    /* 
    * (non-Javadoc) 
    * 
    * @see jdkproxy.Service#add() 
    */ 
    public void add() { 
        System.out.println("AService add>>>>>>>>>>>>>>>>>>"); 
    } 

    /* 
    * (non-Javadoc) 
    * 
    * @see jdkproxy.Service#update() 
    */ 
    public void update() { 
        System.out.println("AService update>>>>>>>>>>>>>>>"); 
    } 
} 


3、實現動態代理類MyInvocationHandler,實現InvocationHandler接口,並且實現接口中的invoke方法。仔細看invoke方法,就是在該方法中加入切面邏輯的。目標類方法的執行是由mehod.invoke(target,args)這條語句完成。

package jdkproxy; 

import java.lang.reflect.InvocationHandler; 
import java.lang.reflect.Method; 

public class MyInvocationHandler implements InvocationHandler { 
    private Object target; 

    MyInvocationHandler() { 
        super(); 
    } 

    MyInvocationHandler(Object target) { 
        super(); 
        this.target = target; 
    } 

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 
        // 程序執行前加入邏輯,MethodBeforeAdviceInterceptor 
        System.out.println("before-----------------------------"); 
        // 程序執行 
        Object result = method.invoke(target, args); 
        // 程序執行後加入邏輯,MethodAfterAdviceInterceptor 
        System.out.println("after------------------------------"); 
        return result; 
    } 

} 


4、測試類,其中增強的目標對象是由Proxy.newProxyInstance(aService.getClass().getClassLoader(), aService.getClass().getInterfaces(), handler);來生成的。

package jdkproxy; 

import java.lang.reflect.Proxy; 

public class Test { 
    public static void main(String[] args) { 
        Service aService = new AService(); 
        MyInvocationHandler handler = new MyInvocationHandler(aService); 
        // Proxy為InvocationHandler實現類動態創建一個符合某一接口的代理實例 
        Service aServiceProxy = (Service) Proxy.newProxyInstance(aService 
        .getClass().getClassLoader(), aService.getClass() 
        .getInterfaces(), handler); 
        // 由動態生成的代理對象來aServiceProxy 代理執行程序,其中aServiceProxy 符合Service接口 
        aServiceProxy.add(); 
        System.out.println(); 
        aServiceProxy.update(); 
        // 以下是對B的代理 
        // Service bService = new BService(); 
        // MyInvocationHandler handler = new MyInvocationHandler(bService); 
        // Service bServiceProxy = (Service) Proxy.newProxyInstance(bService 
        // .getClass().getClassLoader(), bService.getClass() 
        // .getInterfaces(), handler); 
        // bServiceProxy.add(); 
        // System.out.println(); 
        // bServiceProxy.update(); 
    } 
} 


自此,jdk動態代理來實現AOP攔截機制的代碼已經實現,下面我們看一下攔截的結果,程序輸出結果如下:
before-----------------------------
AService add>>>>>>>>>>>>>>>>>>
after------------------------------
before-----------------------------
AService update>>>>>>>>>>>>>>>
after------------------------------
可以看到,在目標類AService的add和update方法前後已經加入了自定義的切面邏輯,AOP攔截機制生效了。

二、cglib動態代理實現AOP攔截(代碼中的關鍵地方都添加了註釋)

1、目標類,cglib不需要定義目標類的統一接口

package cglibproxy; 

/** 
* 被代理類,即目標對象target 
* 
*/ 
public class Base { 
/** 
* 一個模擬的add方法 
*/ 
    public void add() { 
        System.out.println("add ------------"); 
    } 
} 


2、實現動態代理類CglibProxy,需要實現MethodInterceptor接口,實現intercept方法。

該代理中在add方法前後加入了自定義的切面邏輯,目標類add方法執行語句為proxy.invokeSuper(object, args);

package cglibproxy; 

import java.lang.reflect.Method; 
import net.sf.cglib.proxy.MethodInterceptor; 
import net.sf.cglib.proxy.MethodProxy; 

/** 
* 此為代理類,用於在pointcut處添加advise 
* 
* 
*/ 
public class CglibProxy implements MethodInterceptor { 

    public Object intercept(Object object, Method method, Object[] args, 
        MethodProxy proxy) throws Throwable { 
        // 添加切面邏輯(advise),此處是在目標類代碼執行之前,即為MethodBeforeAdviceInterceptor。 
        System.out.println("before-------------"); 
        // 執行目標類add方法 
        proxy.invokeSuper(object, args); 
        // 添加切面邏輯(advise),此處是在目標類代碼執行之後,即為MethodAfterAdviceInterceptor。 
        System.out.println("after--------------"); 
        return null; 
    } 

} 

3、獲取增強的目標類的工廠Factory,其中增強的方法類對象是有Enhancer來實現的,代碼如下所示:

package cglibproxy; 

import net.sf.cglib.proxy.Enhancer; 

/** 
* 工廠類,生成增強過的目標類(已加入切入邏輯) 
* 
*/ 
public class Factory { 
    /** 
    * 獲得增強之後的目標類,即添加了切入邏輯advice之後的目標類 
    * 
    * @return 
    */ 
    public static Base getInstance(CglibProxy proxy) { 
        Enhancer enhancer = new Enhancer(); 
        enhancer.setSuperclass(Base.class); 
        //回調方法的參數為代理類對象CglibProxy,最後增強目標類調用的是代理類對象CglibProxy中的intercept方法 
        enhancer.setCallback(proxy); 
        // 此刻,base不是單純的目標類,而是增強過的目標類 
        Base base = (Base) enhancer.create(); 
        return base; 
    } 
} 


4、測試類

package cglibproxy; 

public class Test { 
    public static void main(String[] args) { 
        CglibProxy proxy = new CglibProxy(); 
        // base為生成的增強過的目標類 
        Base base = Factory.getInstance(proxy); 
        base.add(); 
    } 
} 

自此,cglib動態代理實現的AOP攔截機制已經基本實現,下面我們來看一下攔截的效果如何,程序執行結果如下:
before-------------
add ------------
after--------------
可以看到,在目標類Base的add方法前後已經加入了自定義的切面邏輯,AOP攔截機制生效了。
此外,需要說明一下的是,cglib動態代理用到了第三方類庫,需要在項目中引入兩個jar包:cglib.jar和asm.jar。稍後會在csdn資源中上傳這兩個jar包。免積分的啊。
jar包和相關代碼請見http://download.csdn.net/detail/dreamrealised/6427885

總之,AOP的核心機制和基本功能已經能夠通過動態代理來實現了,至於AOP中,如何從配置文檔中得到目標類target、advisor的bean,如何判斷攔截器類型等問題,就借助於Spring中另一個核心IOC來解決了,後續會有IOC的核心實現機制講解。

Java 動態代理及AOP實現機制