JAVA的動態代理機制

前文講解了代理的基本概念和靜態代理機制:       設計模式之代理模式               
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接口.ide

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

翻譯的很拗口,不要緊,代會看代碼的執行流程就明白了.this

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

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

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

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));
    }
}
相關文章
相關標籤/搜索