欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java JDK動(dòng)態(tài)代理在攔截器和聲明式接口中的應(yīng)用小結(jié)

 更新時(shí)間:2025年01月21日 11:31:58   作者:碼到三十五  
Java動(dòng)態(tài)代理技術(shù)通過(guò)反射機(jī)制在運(yùn)行時(shí)動(dòng)態(tài)生成代理類(lèi),實(shí)現(xiàn)對(duì)目標(biāo)對(duì)象方法的攔截和增強(qiáng),本文給大家介紹Java JDK動(dòng)態(tài)代理在攔截器和聲明式接口中的應(yīng)用小結(jié),感興趣的朋友跟隨小編一起看看吧

一、動(dòng)態(tài)代理概念回顧

Java動(dòng)態(tài)代理技術(shù)是基于反射機(jī)制的基礎(chǔ)。核心在于利用反射機(jī)制和接口編程在運(yùn)行時(shí)動(dòng)態(tài)生成代理類(lèi),并通過(guò)InvocationHandler接口實(shí)現(xiàn)代理邏輯的靈活擴(kuò)展。通過(guò)動(dòng)態(tài)代理,Java程序可以在運(yùn)行時(shí)動(dòng)態(tài)地生成代理類(lèi),并控制對(duì)目標(biāo)對(duì)象的訪問(wèn),從而實(shí)現(xiàn)對(duì)目標(biāo)對(duì)象方法的攔截和增強(qiáng)。
其優(yōu)勢(shì)在于靈活性、可擴(kuò)展性、解耦、AOP支持和遠(yuǎn)程方法調(diào)用等方面.

Java動(dòng)態(tài)代理原理主要基于Java的反射機(jī)制,通過(guò)動(dòng)態(tài)地生成代理類(lèi)來(lái)實(shí)現(xiàn)對(duì)接口的動(dòng)態(tài)代理。

二、 核心組件

  • java.lang.reflect.Proxy 類(lèi):這是Java動(dòng)態(tài)代理的核心類(lèi),提供了創(chuàng)建動(dòng)態(tài)代理實(shí)例的靜態(tài)方法。
  • java.lang.reflect.InvocationHandler:該接口定義了一個(gè)方法 invoke(Object proxy, Method method, Object[] args),代理實(shí)例在調(diào)用接口方法時(shí),會(huì)調(diào)用此方法。

三、工作流程

  • 定義業(yè)務(wù)接口:首先,需要定義一個(gè)或多個(gè)業(yè)務(wù)接口,這些接口將被動(dòng)態(tài)代理。
  • 實(shí)現(xiàn)InvocationHandler接口:創(chuàng)建一個(gè)實(shí)現(xiàn)了InvocationHandler接口的類(lèi),在該類(lèi)的invoke方法中編寫(xiě)代理邏輯。invoke方法會(huì)在代理對(duì)象調(diào)用接口方法時(shí)被自動(dòng)調(diào)用。
  • 生成代理實(shí)例:通過(guò)Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)方法生成代理實(shí)例。這個(gè)方法接收三個(gè)參數(shù):
    • ClassLoader loader:類(lèi)加載器,用于加載代理類(lèi)。
    • Class<?>[] interfaces:一個(gè)接口數(shù)組,代理類(lèi)將實(shí)現(xiàn)這些接口。
    • InvocationHandler h:當(dāng)代理對(duì)象的方法被調(diào)用時(shí),會(huì)調(diào)用此處理器的invoke方法。
  • 調(diào)用代理實(shí)例的方法:當(dāng)調(diào)用代理實(shí)例的方法時(shí),實(shí)際上會(huì)調(diào)用InvocationHandlerinvoke方法,然后可以在invoke方法中執(zhí)行自定義邏輯,并調(diào)用實(shí)際接口實(shí)現(xiàn)的方法。
  • 動(dòng)態(tài)生成字節(jié)碼Proxy.newProxyInstance 方法內(nèi)部會(huì)動(dòng)態(tài)生成一個(gè)實(shí)現(xiàn)了指定接口的代理類(lèi)字節(jié)碼。這個(gè)代理類(lèi)會(huì)重寫(xiě)接口中的所有方法,并在方法內(nèi)部調(diào)用InvocationHandlerinvoke方法。JDK生成的代理類(lèi)名稱通常為com.sun.proxy.$ProxyN,其中N是一個(gè)遞增的數(shù)字,表示這是第幾個(gè)動(dòng)態(tài)生成的代理類(lèi)。

四、動(dòng)態(tài)代理的應(yīng)用場(chǎng)景

動(dòng)態(tài)代理的兩個(gè)最常用見(jiàn)應(yīng)用場(chǎng)景為 攔截器聲明性接口

4.1 搭載器(AOP)

搭載器就是將目標(biāo)組件劫持,在執(zhí)行目標(biāo)組件代碼的前后,塞入一些其它代碼。比如在正式執(zhí)行業(yè)務(wù)方法前,先進(jìn)行權(quán)限校驗(yàn),如果校驗(yàn)不通過(guò),則拒絕繼續(xù)執(zhí)行。對(duì)于此類(lèi)操作,業(yè)界已經(jīng)抽象出一組通用的編程模型:面向切面編程AOP。

接口定義和實(shí)現(xiàn)

public interface Performer {
    void play(String subject);
    String introduction();
}
public interface Director {
    List<String> getCreations();
}
public class DefaultActor implements Performer {
    @Override
    public void play(String subject) {
        System.out.println("[DefaultActor]: 默認(rèn)男演員正在即興表演《" + subject + "》");
    }
    @Override
    public String introduction() {
        return "李白·上李邕: 大鵬一日同風(fēng)起,扶搖直上九萬(wàn)里。假令風(fēng)歇時(shí)下來(lái),猶能顛卻滄溟水。世人見(jiàn)我恒殊調(diào),聞?dòng)啻笱越岳湫?。宣父尚能畏后生,丈夫未可輕年少。";
    }
}
public class DefaultDirector implements Director {
    @Override
    public List<String> getCreations() {
        List<String> creations = new ArrayList<>();
        creations.add("《霸王別姬》");
        creations.add("《活著》");
        return creations;
    }
}

攔截器核心類(lèi)

攔截器核心類(lèi)實(shí)現(xiàn)了InvocationHandler接口,并在invoke方法中插入攔截邏輯。

package guzb.diy.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class ProxyForInterceptor implements InvocationHandler {
    private Object target;
    public ProxyForInterceptor(Object target) {
        this.target = target;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("前置攔截邏輯:開(kāi)始執(zhí)行 " + method.getName() + " 方法");
        Object result = method.invoke(target, args);
        System.out.println("后置攔截邏輯:完成執(zhí)行 " + method.getName() + " 方法");
        return result;
    }
}

測(cè)試

public class IntercepterTestMain {
    public static void main(String[] args) {
        // 創(chuàng)建原始對(duì)象
        Performer actor = new DefaultActor();
        Director director = new DefaultDirector();
        // 創(chuàng)建代理對(duì)象
        Performer actorProxy = (Performer) Proxy.newProxyInstance(
                Performer.class.getClassLoader(),
                new Class[]{Performer.class},
                new ProxyForInterceptor(actor)
        );
        Director directorProxy = (Director) Proxy.newProxyInstance(
                Director.class.getClassLoader(),
                new Class[]{Director.class},
                new ProxyForInterceptor(director)
        );
        // 通過(guò)代理對(duì)象調(diào)用方法
        actorProxy.play("京劇");
        System.out.println(actorProxy.introduction());
        System.out.println("導(dǎo)演的作品集:");
        directorProxy.getCreations().forEach(System.out::println);
    }
}

4.2 聲明是接口

MyBatis中,聲明式接口(通過(guò)注解@Select、@Insert等)允許直接在接口方法上通過(guò)注解來(lái)定義SQL語(yǔ)句,而不需要編寫(xiě)具體的SQL實(shí)現(xiàn)類(lèi)。這種方式使得代碼更加簡(jiǎn)潔,易于維護(hù)。

使用JDK動(dòng)態(tài)代理來(lái)模擬MyBatis中的聲明式接口。

定義業(yè)務(wù)接口

先定義一個(gè)業(yè)務(wù)接口,里面包含使用注解定義的SQL操作。

public interface UserMapper {
    @Select("SELECT * FROM user WHERE name = #{name}")
    User findUserByName(String name);
}
// User的POJO類(lèi)
class User {
    private Integer id;
    private String name;
    // getters and setters
}

這里的@Select注解是自定義的,很簡(jiǎn)單就不展示了。

編寫(xiě)InvocationHandler
寫(xiě)一個(gè)InvocationHandler,它會(huì)在運(yùn)行時(shí)解析@Select這些注解,并執(zhí)行相應(yīng)的SQL操作。簡(jiǎn)化版只模擬解析和調(diào)用的過(guò)程。

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class MyBatisInvocationHandler implements InvocationHandler {
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 這里假設(shè)能夠獲取到注解并解析它
        // 實(shí)際上,你需要一個(gè)SQL執(zhí)行器來(lái)執(zhí)行這里定義的SQL
        System.out.println("Executing method: " + method.getName());
        System.out.println("Parameters: " + Arrays.toString(args));
        // 模擬的SQL執(zhí)行結(jié)果
        User user = new User();
        user.setId(1);
        user.setName((String) args[0]);
        return user;
    }
}

生成代理對(duì)象并調(diào)用

最后,我們生成UserMapper接口的代理對(duì)象,并調(diào)用它的方法。

import java.lang.reflect.Proxy;
public class MyBatisProxyDemo {
    public static void main(String[] args) {
        MyBatisInvocationHandler handler = new MyBatisInvocationHandler();
        UserMapper mapper = (UserMapper) Proxy.newProxyInstance(
            UserMapper.class.getClassLoader(),
            new Class[]{UserMapper.class},
            handler
        );
        User user = mapper.findUserByName("Alice");
        System.out.println("Found user: " + user.getName());
    }
}

輸出結(jié)果

Executing method: findUserByName
Parameters: [Alice]
Found user: Alice

到此這篇關(guān)于Java JDK動(dòng)態(tài)代理在攔截器和聲明式接口中的應(yīng)用小結(jié)的文章就介紹到這了,更多相關(guān)JDK動(dòng)態(tài)代理內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • SpringBoot+JWT實(shí)現(xiàn)注冊(cè)、登錄、狀態(tài)續(xù)簽流程分析

    SpringBoot+JWT實(shí)現(xiàn)注冊(cè)、登錄、狀態(tài)續(xù)簽流程分析

    這篇文章主要介紹了SpringBoot+JWT實(shí)現(xiàn)注冊(cè)、登錄、狀態(tài)續(xù)簽【登錄保持】,本文通過(guò)示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-06-06
  • SpringBoot配置MySQL5.7與MySQL8.0的異同點(diǎn)詳解

    SpringBoot配置MySQL5.7與MySQL8.0的異同點(diǎn)詳解

    MySQL 是 Java 開(kāi)發(fā)中最常用的數(shù)據(jù)庫(kù)之一,而 Spring Boot 提供了便捷的配置方式,隨著 MySQL 8.0 的普及,許多開(kāi)發(fā)者需要從 MySQL 5.7 升級(jí)到 8.0,在實(shí)際開(kāi)發(fā)中,二者的配置方式既有相似之處,也有一些需要特別注意的不同點(diǎn),所以本文給大家詳細(xì)介紹了它們的異同點(diǎn)
    2024-12-12
  • 詳解java 三種調(diào)用機(jī)制(同步、回調(diào)、異步)

    詳解java 三種調(diào)用機(jī)制(同步、回調(diào)、異步)

    這篇文章主要介紹了java 三種調(diào)用機(jī)制(同步、回調(diào)、異步),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-04-04
  • Spring的@Value如何從Nacos配置中心獲取值并自動(dòng)刷新

    Spring的@Value如何從Nacos配置中心獲取值并自動(dòng)刷新

    這篇文章主要介紹了Spring的@Value如何從Nacos配置中心獲取值并自動(dòng)刷新,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-07-07
  • k8s部署MongDB全過(guò)程

    k8s部署MongDB全過(guò)程

    文章介紹了如何在Kubernetes集群中部署MongoDB,包括環(huán)境準(zhǔn)備、創(chuàng)建Secret、創(chuàng)建服務(wù)和Deployment,并通過(guò)Robo3T工具測(cè)試連接
    2025-01-01
  • Spring Boot開(kāi)啟遠(yuǎn)程調(diào)試的方法

    Spring Boot開(kāi)啟遠(yuǎn)程調(diào)試的方法

    這篇文章主要介紹了Spring Boot開(kāi)啟遠(yuǎn)程調(diào)試的方法,幫助大家更好的理解和使用Spring Boot框架,感興趣的朋友可以了解下
    2020-10-10
  • Java中Stringbuilder和正則表達(dá)式示例詳解

    Java中Stringbuilder和正則表達(dá)式示例詳解

    Java語(yǔ)言為字符串連接運(yùn)算符(+)提供特殊支持,并為其他對(duì)象轉(zhuǎn)換為字符串,字符串連接是通過(guò)StringBuilder(或StringBuffer)類(lèi)及其append方法實(shí)現(xiàn)的,這篇文章主要給大家介紹了關(guān)于Java中Stringbuilder和正則表達(dá)式的相關(guān)資料,需要的朋友可以參考下
    2024-02-02
  • 基于Spring Batch 配置重試邏輯

    基于Spring Batch 配置重試邏輯

    這篇文章主要介紹了Spring Batch 配置重試邏輯,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • Java commons-httpclient如果實(shí)現(xiàn)get及post請(qǐng)求

    Java commons-httpclient如果實(shí)現(xiàn)get及post請(qǐng)求

    這篇文章主要介紹了Java commons-httpclient如果實(shí)現(xiàn)get及post請(qǐng)求,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-09-09
  • Java簡(jiǎn)單實(shí)現(xiàn)線程池

    Java簡(jiǎn)單實(shí)現(xiàn)線程池

    這篇文章主要為大家詳細(xì)介紹了Java簡(jiǎn)單實(shí)現(xiàn)線程池,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-04-04

最新評(píng)論