JAVA的動態代理機制

前文講解了代理的基本概念和靜態代理機制:       設計模式之代理模式               

現在來談談JAVA的動態代理機制

在java的動態代理機制中有一個重要的接口invocationhandler和一個重要的類Proxy,讓我們查看一下官方文檔:

InvocationHandler is the interface implemented by the invocation handler of a proxy instance.

Each proxy instance has an associated invocation handler. When a method is invoked on a proxy instance, 
the method invocation is encoded and dispatched to the invoke method of its invocation handler.

代理實例的調用處理程序需要實現InvocationHandler接口.

每個代理實例都關聯了一個調用處理程序.當一個方法被代理實例調用時,這個方法的調用就會被加密並分發到調用程序的調用方法上.

翻譯的很拗口,沒關係,代會看代碼的執行流程就明白了.

這個調用處理程序有一個調用方法:

Object invoke(Object proxy, Method method, Object[] args) throws Throwable

處理代理對象的調用方法並返回結果 .當代理對象綁定的調用程序被調用時,這個方法就會被調用程序調用.

proxy 被調用方法的代理對象

method 代理對象調用接口方法的相應方法.

args 通過代理對象接口調用方法傳入的對象數組.接口方法沒有參數則爲空.

下面來看看proxy的文檔描述:

public class Proxy extends Object implements Serializable
Proxy provides static methods for creating dynamic proxy classes and instances, and it is also the superclass of all dynamic proxy classes created by those methods.

Proxy 提供靜態方法創建動態代理了類和對象,同時也是這些方法創建代理對象的超類.

動態代理類是一個在運行時實現了一系列指定接口的方法的類.代理方法實現代理接口,代理類創建代理對象,每個代理類都關聯了一個實現了InvocationcationHandler接口的調用程序.代理對象的調用方法通過他的代理接口,被分發到實例調用程序的invoke方法上.通過反射機制,這個指定的方法就被調用了,並且傳入一個對象數組.

  • Proxy的一些properties:

  • Proxy類是public,final,和非抽象的

  • 代理類無需指定合法的名稱,類名會以"$Proxy"開頭

  • 代理類需要繼承Proxy

  • 代理類需要按順序實現創建時指定的各個接口

  • 如果代理類實現的是非公共接口,那麼它需要被定義在接口的同名包下.

  • 由於代理類在創建時實現了指定的所有接口,所以在類對象上調用getInterfaces,將會返回一個接口列表的數組,調用getMetjods,將會返回實現所有接口方法的數組.調用getMethod將會返回proxy預期的方法.

  • Proxy.isProxyClass 判斷是不是代理方法

  • 代理類的java.security.ProtectionDomain,和系統類一樣在被啓動類加載

  • 每一個代理類都有一個帶慘構造方法,實現InvocationHandler接口,並綁定調用程序到代理對象上.相比通過反射機制去獲取構造方法,代理對象可以通過調用Proxy.newProxyInstance方法來構造代理對象.

代理接口的properties

  • 代理類實現代理接口

  • 每一個代理實例都通過構造方法關聯了一個調用程序.靜態方法Proxy.getInvocationHandler將會返回一個由代理對象指定的調用程序

  • 代理對象的接口方法調用將會被加密和分發到調用處理程序的invoke方法上.

  • hasCode,equals,toString等方法的調用都會被加密和分發到調用程序的invoke方法,接口方法也被同樣的加密和分發.

話不多說,代碼奉上:

首先定義一個接口:

package com.shadow.proxy.dynamicproxy;

/**
 *
 * @author sunny
 */
public interface ITask {
    public void setData(String data);
    public int getCalData(int x);
}

定義一個實現接口業務的真實主題:

package com.shadow.proxy.dynamicproxy;

/**
 *
 * @author sunny
 */
public class TaskImpl implements ITask {

    @Override
    public void setData(String data) {
        System.out.println(data + "data is saved");
    }

    @Override
    public int getCalData(int x) {
        return x * 10;
    }
    
}

最關鍵的最核心的定義代理類:

package com.shadow.proxy.dynamicproxy;

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

/**
 *
 * @author sunny
 */
public class DynamicProxy implements InvocationHandler {

    private Object obj;

    public DynamicProxy(Object obj) {
        this.obj = obj;
    }
    
    
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object result;
        System.out.println("開始執行方法:" + method);
        result = method.invoke(obj, args);
        System.out.println(method + "方法執行結束");
        return result;
    }
    
}

編寫測試文件:

package com.shadow.proxy.dynamicproxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;

/**
 *
 * @author sunny
 */
public class TestProxy {
    public static void main(String[] args){
        ITask realTask = new TaskImpl();
        InvocationHandler handler = new DynamicProxy(realTask);
        ITask proxyTask = (ITask) Proxy.newProxyInstance(realTask.getClass().getClassLoader(), realTask.getClass().getInterfaces(), handler);
        proxyTask.setData("來一個漢堡");
        System.out.println(proxyTask.getCalData(10));
    }
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章