1. 程式人生 > >SpringAop篇 (1) AOP 基礎之動態代理的實現

SpringAop篇 (1) AOP 基礎之動態代理的實現

介紹

Spring AOP 主要通過動態代理來實現的,所以我們需要在介紹 AOP 用法之前,先來介紹下動態代理的用法以及本質。

對於動態代理的理解可以借鑑普通代理模式。我們普通的Java代理需要為一個物件建立專門的代理物件,通過呼叫代理物件,來實現原物件的各種功能。

image.png

而動態代理區別於普通代理方式,動態代理是在執行時產生的代理類。

動態代理實現方式

  • 通過實現 InvocationHandler 介面建立自己的呼叫處理器;

  • 通過為 Proxy 類指定 ClassLoader 物件和一組 interface 來建立動態代理類;

  • 通過反射機制獲得動態代理類的建構函式,其唯一引數型別是呼叫處理器介面型別;

  • 通過建構函式建立動態代理類例項,構造時呼叫處理器物件作為引數被傳入。

  • 介面:

public interface Action {
    public int action();
}
  • 實現類:
public class LogAction implements Action{
    public int action(){
        System.out.println("action");
        return 20;
    }
}
  • 代理類 :
public class ActionInvocationHandlerImpl implements InvocationHandler {
    private Object action;

    public ActionInvocationHandlerImpl(Object action)
    {
        this.action = action;
    }


    public Action getAction(){
        return (Action) Proxy.newProxyInstance(action.getClass().getClassLoader(),
                action.getClass().getInterfaces(),
                this);

    }
    /**
     * <pre>
     *     動態代理具體的實現類
     * </pre>
     *
     * @param proxy 具體的代理物件
     * @param method 當前呼叫的方法
     * @param args 呼叫引數
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        System.out.println("Before action");
        Object value = method.invoke(action, args);
        System.out.println("End action");

        return value;
    }
}
  • 例子
public class Main {
    public static void main(String[] args) {
        Action action = new ActionInvocationHandlerImpl(new LogAction()).getAction();
        action.action();
    }
}

說明:

每一個動態代理類都必須要實現 InvocationHandler 這個介面(程式碼中的中介),並且每個代理類的例項都關聯到了一個handler,當我們通過代理物件呼叫一個方法的時候,這個方法的呼叫就會被轉發為由InvocationHandler這個介面的 invoke(對方法的增強就寫在這裡面) 方法來進行呼叫。

Proxy這個類的作用就是用來動態建立一個代理物件的類,它提供了許多的方法,但是我們用的最多的就是 newProxyInstance 這個方法:

public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,  InvocationHandler h)  throws IllegalArgumentException

 
//loader:一個ClassLoader物件,定義了由哪個ClassLoader物件來對生成的代理物件進行載入
//interfaces:一個Interface物件的陣列,表示的是我將要給我需要代理的物件提供一組什麼介面,如果我提供了一組介面給它,那麼這個代理物件就宣稱實現了該介面(多型),這樣我就能呼叫這組介面中的方法了
//h:一個InvocationHandler物件,表示的是當我這個動態代理物件在呼叫方法的時候,會關聯到哪一個InvocationHandler物件上