国产av日韩一区二区三区精品,成人性爱视频在线观看,国产,欧美,日韩,一区,www.成色av久久成人,2222eeee成人天堂

首頁 Java Java基礎(chǔ) Java動態(tài)代理的原理

Java動態(tài)代理的原理

Nov 29, 2019 pm 05:06 PM
java

Java動態(tài)代理的原理

Java動態(tài)代理機制的出現(xiàn),使得 Java 開發(fā)人員不用手動編寫代理類,只要簡單地指定一組接口及委託類對象,便能動態(tài)地獲得代理類。 (建議:java影片教學

代理程式類別會負責將所有的方法呼叫分派到委託物件上反射執(zhí)行,在分派執(zhí)行的過程中,開發(fā)人員也可以按需調(diào)整委託類物件及其功能,這是一套非常靈活有彈性的代理框架。下面我們開始動態(tài)代理的學習。

動態(tài)代理程式的簡要說明

在java的動態(tài)代理機制中,有兩個重要的類別或接口,一個是InvocationHandler( Interface)、另一個則是Proxy(Class)。

一、 InvocationHandler(interface)的描述:

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.

每一個動態(tài)代理類別都必須要實作InvocationHandler這個接口,並且每個代理類別的實例都關(guān)聯(lián)到了一個handler,當我們透過代理物件呼叫一個方法的時候,這個方法的呼叫就會被轉(zhuǎn)發(fā)為由InvocationHandler這個介面的invoke 方法來進行呼叫。我們來看看InvocationHandler這個介面的唯一一個方法?invoke 方法:

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

這個方法接收三個參數(shù)和回傳一個Object類型,它們分別代表的意思如下:

proxy: 指涉我們所代理的那個真實物件

method: 指涉的是我們所要呼叫真實物件的方法的Method物件

args: 指涉的是呼叫真實物件某個方法時所接受的參數(shù)

傳回的Object是指真實物件方法的回傳類型,以上會在接下來的例子中加以深入理解。

the value to return from the method invocation on the proxy instance.

二、 Proxy(Class)的描述:

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)建立一個代理物件。我們常用的是newProxyInstance這個方法:

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

?參數(shù)的理解:

// 一個ClassLoader對象,定義了由哪個ClassLoader對象來對生成的代理對象進行加載
loader - the class loader to define the proxy class  
// 一個Interface對象的數(shù)組,表示的是我將要給我需要代理的對象提供一組什么接口
interfaces - the list of interfaces for the proxy class to implement 
// 一個InvocationHandler對象,表示的是當我這個動態(tài)代理對象在調(diào)用方法的時候,會關(guān)聯(lián)到哪一個InvocationHandler對象上
h - the invocation handler to dispatch method invocations to

傳回結(jié)果的理解: 一個代理物件的實例

##a proxy instance with the specified invocation handler of a proxy class that is defined by the specified class loader and that implements the specified interfaces?

簡單的Java代理

#我們創(chuàng)建一個Java項目用於對動態(tài)代理的測試與理解,專案架構(gòu)如下:

Java動態(tài)代理的原理

一、 先定義一個介面Interface,新增兩個方法。

package com.huhx.proxy;

public interface Interface {
    void getMyName();

    String getNameById(String id);
}

二、 定義一個真實的實作上述介面的類,RealObject:

package com.huhx.proxy;

public class RealObject implements Interface {
    @Override
    public void getMyName() {
        System.out.println("my name is huhx");
    }

    @Override
    public String getNameById(String id) {
        System.out.println("argument id: " + id);
        return "huhx";
    }
}

三、 定義一個代理對象,也實現(xiàn)了上述的Interface介面:

package com.huhx.proxy;

public class SimpleProxy implements Interface {
    private Interface proxied;

    public SimpleProxy(Interface proxied) {
        this.proxied = proxied;
    }

    @Override
    public void getMyName() {
        System.out.println("proxy getmyname");
        proxied.getMyName();
    }

    @Override
    public String getNameById(String id) {
        System.out.println("proxy getnamebyid");
        return proxied.getNameById(id);
    }
}

四、 SimpleMain在Main方法中,測試上述的結(jié)果:

package com.huhx.proxy;

public class SimpleMain {
    private static void consume(Interface iface) {
        iface.getMyName();
        String name = iface.getNameById("1");
        System.out.println("name: " + name);
    }

    public static void main(String[] args) {
        consume(new RealObject());
        System.out.println("========================================================");
        consume(new SimpleProxy(new RealObject()));
    }
}

五、運行的結(jié)果如下:

my name is huhx
argument id: 1
name: huhx
========================================================
proxy getmyname
my name is huhx
proxy getnamebyid
argument id: 1
name: huhx

Java的動態(tài)代理

完成了上述簡單的Java代理,現(xiàn)在我們開始學習Java的動態(tài)代理,它比代理的思想更向前一步,因為它可以動態(tài)地創(chuàng)建代理並動態(tài)的處理對所代理方法的呼叫。在動態(tài)代理上所做的所有呼叫都會被重新導(dǎo)向到單一的呼叫處理器上,它的工作是揭示呼叫的類型並確定相應(yīng)的對策。下面我們透過案例來加深Java動態(tài)代理的理解:

一、 建立一個繼承了InvocationHandler的處理器:DynamicProxyHandler

package com.huhx.dynamicproxy;

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

public class DynamicProxyHandler implements InvocationHandler {
    private Object proxied;

    public DynamicProxyHandler(Object proxied) {
        System.out.println("dynamic proxy handler constuctor: " + proxied.getClass());
        this.proxied = proxied;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("dynamic proxy name: " + proxy.getClass());
        System.out.println("method: " + method.getName());
        System.out.println("args: " + Arrays.toString(args));
        
        Object invokeObject = method.invoke(proxied, args);
        if (invokeObject != null) {
            System.out.println("invoke object: " + invokeObject.getClass());
        } else {
            System.out.println("invoke object is null");
        }
        return invokeObject;
    }
}

#?二、 我們寫一個測試的Main方法,DynamicProxyMain:

package com.huhx.dynamicproxy;

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

import com.huhx.proxy.Interface;
import com.huhx.proxy.RealObject;

public class DynamicProxyMain {
    public static void consumer(Interface iface) {
        iface.getMyName();
        String name = iface.getNameById("1");
        System.out.println("name: " + name);
    }

    public static void main(String[] args) throws Exception, SecurityException, Throwable {
        RealObject realObject = new RealObject();
        consumer(realObject);
        System.out.println("==============================");

        // 動態(tài)代理
        ClassLoader classLoader = Interface.class.getClassLoader();
        Class<?>[] interfaces = new Class[] { Interface.class };
        InvocationHandler handler = new DynamicProxyHandler(realObject);
        Interface proxy = (Interface) Proxy.newProxyInstance(classLoader, interfaces, handler);

        System.out.println("in dynamicproxyMain proxy: " + proxy.getClass());
        consumer(proxy);
    }
}

三、 運行結(jié)果如下:

my name is huhx
argument id: 1
name: huhx
==============================
dynamic proxy handler constuctor: class com.huhx.proxy.RealObject
in dynamicproxyMain proxy: class com.sun.proxy.$Proxy0
dynamic proxy name: class com.sun.proxy.$Proxy0
method: getMyName
args: null
my name is huhx
invoke object is null
dynamic proxy name: class com.sun.proxy.$Proxy0
method: getNameById
args: [1]
argument id: 1
invoke object: class java.lang.String
name: huhx

從以上輸出結(jié)果,我們可以得到以下結(jié)論:

與代理物件相關(guān)聯(lián)的InvocationHandler,只有在代理物件呼叫方法時,才會執(zhí)行它的invoke方法

invoke的三個參數(shù)的理解:Object proxy是代理的物件, Method method是真實物件中呼叫方法的Method類別, Object[] args是真實物件中呼叫方法的參數(shù)

Java動態(tài)代理程式的原理

一、動態(tài)代理程式的關(guān)鍵程式碼就是Proxy.newProxyInstance(classLoader, interfaces, handler),我們跟進原始碼看看:

public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException {
  // handler不能為空
    if (h == null) {
        throw new NullPointerException();
    }

    final Class<?>[] intfs = interfaces.clone();
    final SecurityManager sm = System.getSecurityManager();
    if (sm != null) {
        checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
    }

    /*
     * Look up or generate the designated proxy class.
     */
  // 通過loader和接口,得到代理的Class對象
    Class<?> cl = getProxyClass0(loader, intfs);

    /*
     * Invoke its constructor with the designated invocation handler.
     */
    try {
        final Constructor<?> cons = cl.getConstructor(constructorParams);
        final InvocationHandler ih = h;
        if (sm != null && ProxyAccessHelper.needsNewInstanceCheck(cl)) {
            // create proxy instance with doPrivilege as the proxy class may
            // implement non-public interfaces that requires a special permission
            return AccessController.doPrivileged(new PrivilegedAction<Object>() {
                public Object run() {
                    return newInstance(cons, ih);
                }
            });
        } else {
       // 創(chuàng)建代理對象的實例
            return newInstance(cons, ih);
        }
    } catch (NoSuchMethodException e) {
        throw new InternalError(e.toString());
    }
}

#二、 我們看一下newInstance方法的原始碼:

private static Object newInstance(Constructor<?> cons, InvocationHandler h) {
    try {
        return cons.newInstance(new Object[] {h} );
    } catch (IllegalAccessException | InstantiationException e) {
        throw new InternalError(e.toString());
    } catch (InvocationTargetException e) {
        Throwable t = e.getCause();
        if (t instanceof RuntimeException) {
            throw (RuntimeException) t;
        } else {
            throw new InternalError(t.toString());
        }
    }
}

三、 當我們透過代理物件呼叫一個方法的時候,這個方法的呼叫就會被轉(zhuǎn)發(fā)為由InvocationHandler這個介面的invoke 方法來進行調(diào)用。

###反映這句話的程式碼,我在原始碼中沒有找到,於是我在測試類別的main方法中加入以下程式碼:###
if (proxy instanceof Proxy) {
    InvocationHandler invocationHandler = Proxy.getInvocationHandler(proxy);
    invocationHandler.invoke(proxy, realObject.getClass().getMethod("getMyName"), null);
    System.out.println("--------------------------------------");
}

這段代碼的輸出結(jié)果如下,與上述中調(diào)用代理對象中的getMyName方法輸出是一樣的,不知道Jvm底層是否是這樣判斷的:

dynamic proxy handler constuctor: class com.huhx.proxy.RealObject
dynamic proxy name: class com.sun.proxy.$Proxy0
method: getMyName
args: null
my name is huhx
invoke object is null
--------------------------------------

更多java知識請關(guān)注java基礎(chǔ)教程欄目。

以上是Java動態(tài)代理的原理的詳細內(nèi)容。更多資訊請關(guān)注PHP中文網(wǎng)其他相關(guān)文章!

本網(wǎng)站聲明
本文內(nèi)容由網(wǎng)友自願投稿,版權(quán)歸原作者所有。本站不承擔相應(yīng)的法律責任。如發(fā)現(xiàn)涉嫌抄襲或侵權(quán)的內(nèi)容,請聯(lián)絡(luò)admin@php.cn

熱AI工具

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅(qū)動的應(yīng)用程序,用於創(chuàng)建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發(fā)環(huán)境

Dreamweaver CS6

Dreamweaver CS6

視覺化網(wǎng)頁開發(fā)工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

用雅加達EE在Java建立靜止的API 用雅加達EE在Java建立靜止的API Jul 30, 2025 am 03:05 AM

SetupaMaven/GradleprojectwithJAX-RSdependencieslikeJersey;2.CreateaRESTresourceusingannotationssuchas@Pathand@GET;3.ConfiguretheapplicationviaApplicationsubclassorweb.xml;4.AddJacksonforJSONbindingbyincludingjersey-media-json-jackson;5.DeploytoaJakar

Java項目管理Maven的開發(fā)人員指南 Java項目管理Maven的開發(fā)人員指南 Jul 30, 2025 am 02:41 AM

Maven是Java項目管理和構(gòu)建的標準工具,答案在於它通過pom.xml實現(xiàn)項目結(jié)構(gòu)標準化、依賴管理、構(gòu)建生命週期自動化和插件擴展;1.使用pom.xml定義groupId、artifactId、version和dependencies;2.掌握核心命令如mvnclean、compile、test、package、install和deploy;3.利用dependencyManagement和exclusions管理依賴版本與衝突;4.通過多模塊項目結(jié)構(gòu)組織大型應(yīng)用並由父POM統(tǒng)一管理;5.配

CSS暗模式切換示例 CSS暗模式切換示例 Jul 30, 2025 am 05:28 AM

首先通過JavaScript獲取用戶系統(tǒng)偏好和本地存儲的主題設(shè)置,初始化頁面主題;1.HTML結(jié)構(gòu)包含一個按鈕用於觸發(fā)主題切換;2.CSS使用:root定義亮色主題變量,.dark-mode類定義暗色主題變量,並通過var()應(yīng)用這些變量;3.JavaScript檢測prefers-color-scheme並讀取localStorage決定初始主題;4.點擊按鈕時切換html元素上的dark-mode類,並將當前狀態(tài)保存至localStorage;5.所有顏色變化均帶有0.3秒過渡動畫,提升用戶

CSS下拉菜單示例 CSS下拉菜單示例 Jul 30, 2025 am 05:36 AM

是的,一個常見的CSS下拉菜單可以通過純HTML和CSS實現(xiàn),無需JavaScript。 1.使用嵌套的ul和li構(gòu)建菜單結(jié)構(gòu);2.通過:hover偽類控制下拉內(nèi)容的顯示與隱藏;3.父級li設(shè)置position:relative,子菜單使用position:absolute進行定位;4.子菜單默認display:none,懸停時變?yōu)閐isplay:block;5.可通過嵌套實現(xiàn)多級下拉,結(jié)合transition添加淡入動畫,配合媒體查詢適配移動端,整個方案簡潔且無需JavaScript支持,適合大

如何將Java MistageDigest用於哈希(MD5,SHA-256)? 如何將Java MistageDigest用於哈希(MD5,SHA-256)? Jul 30, 2025 am 02:58 AM

要使用Java生成哈希值,可通過MessageDigest類實現(xiàn)。 1.獲取指定算法的實例,如MD5或SHA-256;2.調(diào)用.update()方法傳入待加密數(shù)據(jù);3.調(diào)用.digest()方法獲取哈希字節(jié)數(shù)組;4.將字節(jié)數(shù)組轉(zhuǎn)換為十六進製字符串以便讀取;對於大文件等輸入,應(yīng)分塊讀取並多次調(diào)用.update();推薦使用SHA-256而非MD5或SHA-1以確保安全性。

Python Parse Date String示例 Python Parse Date String示例 Jul 30, 2025 am 03:32 AM

使用datetime.strptime()可將日期字符串轉(zhuǎn)換為datetime對象,1.基本用法:通過"%Y-%m-%d"解析"2023-10-05"為datetime對象;2.支持多種格式如"%m/%d/%Y"解析美式日期、"%d/%m/%Y"解析英式日期、"%b%d,%Y%I:%M%p"解析帶AM/PM的時間;3.可用dateutil.parser.parse()自動推斷未知格式;4.使用.d

VSCODE設(shè)置。 JSON位置 VSCODE設(shè)置。 JSON位置 Aug 01, 2025 am 06:12 AM

settings.json文件位於用戶級或工作區(qū)級路徑,用於自定義VSCode設(shè)置。 1.用戶級路徑:Windows為C:\Users\\AppData\Roaming\Code\User\settings.json,macOS為/Users//Library/ApplicationSupport/Code/User/settings.json,Linux為/home//.config/Code/User/settings.json;2.工作區(qū)級路徑:項目根目錄下的.vscode/settings

崇高文本自動關(guān)閉HTML標籤 崇高文本自動關(guān)閉HTML標籤 Jul 30, 2025 am 02:41 AM

安裝Emmet插件可實現(xiàn)智能自動閉合標籤並支持縮寫語法;2.啟用"auto_match_enabled":true讓Sublime自動補全簡單標籤;3.使用Alt .(Win)或Ctrl Shift .(Mac)快捷鍵手動閉合當前標籤——推薦日常使用Emmet,輕量需求可用後兩種方式組合,效率足夠且設(shè)置簡單。

See all articles