溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

JAVA的動態(tài)代理機制

發(fā)布時間:2020-07-04 06:42:40 來源:網(wǎng)絡(luò) 閱讀:696 作者:sun2shadows 欄目:軟件技術(shù)

前文講解了代理的基本概念和靜態(tài)代理機制:       設(shè)計模式之代理模式               

現(xiàn)在來談?wù)凧AVA的動態(tài)代理機制

在java的動態(tài)代理機制中有一個重要的接口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.

代理實例的調(diào)用處理程序需要實現(xiàn)InvocationHandler接口.

每個代理實例都關(guān)聯(lián)了一個調(diào)用處理程序.當(dāng)一個方法被代理實例調(diào)用時,這個方法的調(diào)用就會被加密并分發(fā)到調(diào)用程序的調(diào)用方法上.

翻譯的很拗口,沒關(guān)系,代會看代碼的執(zhí)行流程就明白了.

這個調(diào)用處理程序有一個調(diào)用方法:

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

處理代理對象的調(diào)用方法并返回結(jié)果 .當(dāng)代理對象綁定的調(diào)用程序被調(diào)用時,這個方法就會被調(diào)用程序調(diào)用.

proxy 被調(diào)用方法的代理對象

method 代理對象調(diào)用接口方法的相應(yīng)方法.

args 通過代理對象接口調(diào)用方法傳入的對象數(shù)組.接口方法沒有參數(shù)則為空.

下面來看看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 提供靜態(tài)方法創(chuàng)建動態(tài)代理了類和對象,同時也是這些方法創(chuàng)建代理對象的超類.

動態(tài)代理類是一個在運行時實現(xiàn)了一系列指定接口的方法的類.代理方法實現(xiàn)代理接口,代理類創(chuàng)建代理對象,每個代理類都關(guān)聯(lián)了一個實現(xiàn)了InvocationcationHandler接口的調(diào)用程序.代理對象的調(diào)用方法通過他的代理接口,被分發(fā)到實例調(diào)用程序的invoke方法上.通過反射機制,這個指定的方法就被調(diào)用了,并且傳入一個對象數(shù)組.

  • Proxy的一些properties:

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

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

  • 代理類需要繼承Proxy

  • 代理類需要按順序?qū)崿F(xiàn)創(chuàng)建時指定的各個接口

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

  • 由于代理類在創(chuàng)建時實現(xiàn)了指定的所有接口,所以在類對象上調(diào)用getInterfaces,將會返回一個接口列表的數(shù)組,調(diào)用getMetjods,將會返回實現(xiàn)所有接口方法的數(shù)組.調(diào)用getMethod將會返回proxy預(yù)期的方法.

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

  • 代理類的java.security.ProtectionDomain,和系統(tǒng)類一樣在被啟動類加載

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

代理接口的properties

  • 代理類實現(xiàn)代理接口

  • 每一個代理實例都通過構(gòu)造方法關(guān)聯(lián)了一個調(diào)用程序.靜態(tài)方法Proxy.getInvocationHandler將會返回一個由代理對象指定的調(diào)用程序

  • 代理對象的接口方法調(diào)用將會被加密和分發(fā)到調(diào)用處理程序的invoke方法上.

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

話不多說,代碼奉上:

首先定義一個接口:

package com.shadow.proxy.dynamicproxy;

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

定義一個實現(xiàn)接口業(yè)務(wù)的真實主題:

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;
    }
    
}

最關(guān)鍵的最核心的定義代理類:

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("開始執(zhí)行方法:" + method);
        result = method.invoke(obj, args);
        System.out.println(method + "方法執(zhí)行結(jié)束");
        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));
    }
}


向AI問一下細節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI