最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

JavaSE反射與動(dòng)態(tài)代理詳細(xì)代碼示例

 更新時(shí)間:2026年04月01日 10:02:09   作者:無(wú)止境ww  
Java反射和動(dòng)態(tài)代理是Java中兩個(gè)強(qiáng)大的特性,它們?cè)试S程序在運(yùn)行時(shí)動(dòng)態(tài)地獲取和操作類、方法、字段等信息,以及創(chuàng)建代理對(duì)象來(lái)實(shí)現(xiàn)AOP等功能,這篇文章主要介紹了JavaSE反射與動(dòng)態(tài)代理的相關(guān)資料,需要的朋友可以參考下

一、引言

在Java生態(tài)中,反射與動(dòng)態(tài)代理是支撐框架設(shè)計(jì)的基石,無(wú)論是Spring中的AOP,還是Mybatis的Mapper接口,都離不開(kāi)這兩項(xiàng)技術(shù)。在學(xué)習(xí)之前先了解反射和動(dòng)態(tài)代理分別可以做什么,簡(jiǎn)單說(shuō)反射賦予程序“看清類結(jié)構(gòu)”的功能,通過(guò)反射可以知道類中構(gòu)造方法,成員方法,成員變量等信息;動(dòng)態(tài)代理則實(shí)現(xiàn)了“無(wú)侵入式增強(qiáng)”,二者相輔相成,讓代碼具備靈活性與擴(kuò)展性。

二、Java反射:探索類的“隱藏世界”

2.1 反射的定義

在Java中,反射(Reflection)是一種強(qiáng)大的機(jī)制,允許程序在運(yùn)行時(shí)檢查或修改其自身的結(jié)構(gòu)和行為。通過(guò)反射,你可以查詢類的元數(shù)據(jù)(如類名、方法、字段、注解等),動(dòng)態(tài)地進(jìn)行創(chuàng)建對(duì)象,調(diào)用方法,訪問(wèn)字段等操作。

2.2反射的核心API

Java反射的核心操作集中在java.lang.reflect包中,其中關(guān)鍵類包括Class、Method、Field、Constructor,核心操作分為“獲取Class對(duì)象”“操作類成員”兩步

(1)如何獲取類對(duì)象?

首先在這里定義一個(gè)User類

public class User {
    private String name;
    public Integer age;
    public User(){}
    private User(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
    private void setAge(Integer age) {
        this.age = age;
    }
}

獲取類對(duì)象有三種方式分別是:類名.class,對(duì)象.getClass(),Class.forName(“全類名”)

        //1.類名.class(編譯時(shí)確定,最高效)
        Class<?> class1 = User.class;
        System.out.println(class1); //class User
        //2.對(duì)象.getClass() (運(yùn)行時(shí)獲取,需要實(shí)例化)
        User user = new User();
        Class<?> class2 = user.getClass();
        System.out.println(class2); //class User
        //3.Class.forName("全類名") (運(yùn)行時(shí)加載,最靈活)
        Class<?> class3 = Class.forName("User");
        System.out.println(class3); //class User
        //判斷上面三種方法獲取的是否是同一個(gè)對(duì)象
        System.out.println(class1.equals(class2)); //true

(2) 利用反射操作類

得到類成員后就可以利用反射操作類的構(gòu)造方法,成員方法,成員變量等元數(shù)據(jù),核心API也很易懂

示例1. 構(gòu)造器

//1.獲取類
        Class<User> userClass = User.class;
        //2.獲取構(gòu)造器
        //2.1獲取公共構(gòu)造器
        Constructor<?>[] publicConstructors = userClass.getConstructors();
        System.out.println(Arrays.toString(publicConstructors)); //[public User()]
        //2.2獲取所有構(gòu)造器
        Constructor<?>[] declaredConstructors = userClass.getDeclaredConstructors();
        System.out.println(Arrays.toString(declaredConstructors)); //[public User(), private User(java.lang.String)]
        //2.3獲取一個(gè)公共構(gòu)造器 (可以傳遞參數(shù),參數(shù)是構(gòu)造器中的形參類)
        Constructor<User> constructor = userClass.getConstructor();
        System.out.println(constructor); //public User()
        //2.4獲取一個(gè)構(gòu)造器 (可以傳遞參數(shù),參數(shù)是構(gòu)造器中的形參類)
        Constructor<User> declaredConstructor = userClass.getDeclaredConstructor(String.class);
        System.out.println(declaredConstructor); // private User(java.lang.String)

然后可以對(duì)獲得的構(gòu)造器進(jìn)行操作:

//2.4獲取一個(gè)構(gòu)造器
		Constructor<User> declaredConstructor = userClass.getDeclaredConstructor(String.class);
        System.out.println(declaredConstructor); // private User(java.lang.String)
		//3.Constructor類常用方法
        //3.1獲取構(gòu)造器的權(quán)限修飾符
        int modifiers = declaredConstructor.getModifiers();
        System.out.println(declaredConstructor + "的構(gòu)造方法的修飾符為" + modifiers);//private User(java.lang.String)的構(gòu)造方法的修飾符為2(對(duì)應(yīng)private)
        //3.2獲取構(gòu)造器的形參類型
        Class<?>[] types = declaredConstructor.getParameterTypes();
        System.out.println(declaredConstructor + "的形參類型有" + Arrays.toString(types)); //private User(java.lang.String)的形參類型有[class java.lang.String]
        //3.3通過(guò)Constructor實(shí)例化對(duì)象
        //因?yàn)楂@取的是私有方法,所以需要暴力反射
        declaredConstructor.setAccessible(true);//將私有構(gòu)造器設(shè)置為可訪問(wèn)狀態(tài)
        User user = declaredConstructor.newInstance( "無(wú)止境"); 
        System.out.println(user.getName()); //無(wú)止境

在 Java 中,java.lang.reflect.Constructor類的getModifiers()方法返回一個(gè)整數(shù),該整數(shù)是構(gòu)造器修飾符的位掩碼(Bitmask)。每個(gè)修飾符對(duì)應(yīng)一個(gè)二進(jìn)制位,不同修飾符通過(guò)按位或(OR)組合成最終的整數(shù)值。

獲取字段,方法等API與獲取構(gòu)造器類似,演示一下通過(guò)反射操作私有成員

    //1.獲取類
        Class<User> userClass = User.class;
        //2.實(shí)例私有構(gòu)造器
        Constructor<User> privateConstructor = userClass.getDeclaredConstructor(String.class);
        privateConstructor.setAccessible(true);
        User user = privateConstructor.newInstance("無(wú)止境");
        //3.調(diào)用私有化方法setAge
        Method setAge = userClass.getDeclaredMethod("setAge", Integer.class);
        setAge.setAccessible(true);
        setAge.invoke(user, 18);
        System.out.println(user.getName() + "的年齡為" + user.getAge()); //無(wú)止境的年齡為18
        //4.獲取私有屬性 name
        Field nameField = userClass.getDeclaredField("name");
        nameField.setAccessible(true);
        String name = (String)nameField.get(user);
        System.out.println("利用反射獲取的私有屬性" + name); //利用反射獲取的私有屬性無(wú)止境

Method類中invoke()方法比較常用,傳遞的參數(shù)表示1:調(diào)用方法的對(duì)象, 2:調(diào)用方法傳遞的參數(shù);返回值就是原方法返回值

三、動(dòng)態(tài)代理,無(wú)侵入式增強(qiáng)的實(shí)現(xiàn)利器

3.1動(dòng)態(tài)代理定義

動(dòng)態(tài)代理是一種設(shè)計(jì)模式,允許程序在運(yùn)行時(shí)動(dòng)態(tài)生成代理類,代理類會(huì)包裹目標(biāo)對(duì)象,在不修改目標(biāo)代碼的情況下,對(duì)目標(biāo)方法進(jìn)行增強(qiáng)。Java中動(dòng)態(tài)代理主要分為兩種JDK動(dòng)態(tài)代理和CGLIB動(dòng)態(tài)代理

3.2JDK動(dòng)態(tài)代理(接口增強(qiáng))

(1)核心組件

  • InvocationHandler:定義代理邏輯,所有代理方法的調(diào)用都會(huì)委托給該接口的invoke方法。
  • Proxy:用于創(chuàng)建動(dòng)態(tài)代理類和實(shí)例的工廠

(2)實(shí)現(xiàn)步驟

  1. 定義接口:目標(biāo)類需實(shí)現(xiàn)接口
  2. 實(shí)現(xiàn)InvocationHandler:處理方法調(diào)用邏輯
  3. 生成代理對(duì)象:通過(guò)Proxy.newProxyInstance()創(chuàng)建代理

(3)示例代碼

定義接口:目標(biāo)類需實(shí)現(xiàn)接口

//目標(biāo)接口
public interface UserService {
    void addUser(String name);
    void deleteUser(Integer id);
}
//目標(biāo)實(shí)現(xiàn)類
public class UserServiceImpl implements UserService {
   @Override
    public void addUser(String name) {
        System.out.println("執(zhí)行添加姓名為 : " + name + " 用戶的操作");
    }
    @Override
    public void deleteUser(Integer id) {
        System.out.println("執(zhí)行刪除id為 : " + id + " 用戶的操作");
    }
}

實(shí)現(xiàn)InvocationHandler:處理方法調(diào)用邏輯

public class LogInvocationHandler implements InvocationHandler {
    private Object target; //目標(biāo)對(duì)象
    public LogInvocationHandler(Object target) {
        this.target = target;
    }
    /**
     *
     * @param proxy 代理對(duì)象
     * @param method 目標(biāo)方法
     * @param args 方法參數(shù)
     * @return 方法返回值
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //前置日志,記錄日志
        System.out.println("【日志】 開(kāi)始調(diào)用方法 : " + method.getName() + ",方法參數(shù)為 : " + Arrays.toString(args));
        //調(diào)用目標(biāo)方法
        Object result = method.invoke(target, args);
        //后置日志,記錄方法完成
        System.out.println("【日志】方法調(diào)用結(jié)束 : " + method.getName());
        return result;
    }
}

生成代理對(duì)象:通過(guò)Proxy.newProxyInstance()創(chuàng)建代理

public static void main(String[] args) {
        //1.創(chuàng)建目標(biāo)對(duì)象
        UserServiceImpl target = new UserServiceImpl();
        //2.創(chuàng)建InvocationHandler實(shí)例
        LogInvocationHandler handler = new LogInvocationHandler(target);
        //3.生成動(dòng)態(tài)代理對(duì)象
        UserService proxy = (UserService) Proxy.newProxyInstance(
                target.getClass().getClassLoader(), //類加載器
                target.getClass().getInterfaces(), //目標(biāo)實(shí)現(xiàn)的接口
                handler
        );
        //4.調(diào)用代理對(duì)象的方法
        proxy.addUser("無(wú)止境");
        proxy.deleteUser(1001);
    }

最后控制臺(tái)輸出結(jié)果

【日志】 開(kāi)始調(diào)用方法 : addUser,方法參數(shù)為 : [無(wú)止境]
執(zhí)行添加姓名為 : 無(wú)止境 用戶的操作
【日志】方法調(diào)用結(jié)束 : addUser
【日志】 開(kāi)始調(diào)用方法 : deleteUser,方法參數(shù)為 : [1001]
執(zhí)行刪除id為 : 1001 用戶的操作
【日志】方法調(diào)用結(jié)束 : deleteUser

至此就完成了一個(gè)簡(jiǎn)單的日志增強(qiáng)效果

(4)核心API用法

  • public Object invoke(Object proxy, Method method, Object[] args):三個(gè)參數(shù)分別是代理對(duì)象本身(通常不需要使用);被調(diào)用的目標(biāo)方法;方法參數(shù)數(shù)組。
  • public static Object newProxyInstance(
    ClassLoader loader,
    Class<?>[] interfaces,
    InvocationHandler h
    ):里面要傳遞三個(gè)參數(shù)分別是類加載器(通常使用目標(biāo)接口的類加載器);目標(biāo)接口數(shù)組(至少一個(gè)接口);代理邏輯處理器。

3.3CFLIB實(shí)現(xiàn)動(dòng)態(tài)代理(類增強(qiáng))

(1)核心組件

  • MethodInterceptor:攔截目標(biāo)類的方法調(diào)用,定義增強(qiáng)邏輯
  • Enhancer:生成代理類和實(shí)例的工具

(2)實(shí)現(xiàn)步驟

  1. 引入CGLIB依賴
  2. 定義無(wú)接口的目標(biāo)類
  3. 實(shí)現(xiàn)MethodInterceptor
  4. 生成CGLIB代理對(duì)象:利用Enhancer.create()方法

(3)示例代碼

引入CGLIB依賴(maven)

<dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>3.3.0</version>
        </dependency>
public class OrderService {
    //模擬創(chuàng)建訂單方法
    public void createOrder(String orderNo) {
        System.out.println("創(chuàng)建訂單,訂單號(hào)為 : " + orderNo);
    }
}

自定義類實(shí)現(xiàn)MethodInterceptor,處理方法調(diào)用邏輯

public class TransactionMethodInterceptor implements MethodInterceptor {
    /**
     *
     * @param o 目標(biāo)對(duì)象
     * @param method 目標(biāo)方法
     * @param objects 方法參數(shù)
     * @param methodProxy 方法代理對(duì)象
     * @return 方法返回值
     * @throws Throwable
     */
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        //前置增強(qiáng):開(kāi)啟事務(wù)
        System.out.println("【事務(wù)】開(kāi)啟數(shù)據(jù)事務(wù)");
        //調(diào)用目標(biāo)方法(通過(guò)methodProxy提高性能)
        Object result = methodProxy.invokeSuper(o, objects);
        //后置增強(qiáng):提交事務(wù)
        System.out.println("【事務(wù)】提交數(shù)據(jù)事務(wù)");
        return result;
    }
}

通過(guò)Enhancer.create()生成代理對(duì)象

public class CglibProxyDemo {
    public static void main(String[] args) {
        //1.創(chuàng)建Enhancer實(shí)例(CGLIB核心)
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(OrderService.class); //設(shè)置目標(biāo)類
        enhancer.setCallback(new TransactionMethodInterceptor()); //設(shè)置增強(qiáng)器
        //2.生成動(dòng)態(tài)代理對(duì)象
        OrderService proxy = (OrderService) enhancer.create();
        //3.調(diào)用代理對(duì)象方法
        proxy.createOrder("order_112233");
    }
}

最終輸出結(jié)果:

【事務(wù)】開(kāi)啟數(shù)據(jù)事務(wù)
創(chuàng)建訂單,訂單號(hào)為 : order_112233
【事務(wù)】提交數(shù)據(jù)事務(wù)

(4)核心API用法

  • public void setSuperclass(Class<?> superclass); 指定目標(biāo)類
  • public void setCallback(Callback callback); 設(shè)置攔截器
  • public Object create(); 生成代理實(shí)例
  • public Object intercept(
    Object obj,
    Method method,
    Object[] args,
    MethodProxy proxy
    ):參數(shù)分別是obj:代理對(duì)象(通常不需要使用);method:被調(diào)用的目標(biāo)方法;args:方法參數(shù)數(shù)組;proxy:MethodProxy 對(duì)象,比反射調(diào)用更高效

3.3JDK動(dòng)態(tài)代理和CGLIB動(dòng)態(tài)代理橫向?qū)Ρ?/h3>
組件JDK動(dòng)態(tài)代理CGLIB動(dòng)態(tài)代理
接口InvocationHandlerMethodInterceptor
生成代理方式Proxy.newProxyInstanceEnhancer.create()
目標(biāo)類型接口
調(diào)用目標(biāo)方法method.invoke(target, args)proxy.invokSuper(obj, args)

四、反射與動(dòng)態(tài)代理的實(shí)際應(yīng)用

(1)反射的實(shí)際應(yīng)用

  • Spring 框架:Spring 使用反射來(lái)創(chuàng)建和管理 Bean。例如,通過(guò)配置文件(如 XML 或注解)指定要?jiǎng)?chuàng)建的類,Spring 容器利用反射機(jī)制根據(jù)類名動(dòng)態(tài)加載類,并調(diào)用其構(gòu)造函數(shù)創(chuàng)建對(duì)象實(shí)例。
  • JUnit:JUnit 利用反射來(lái)發(fā)現(xiàn)和執(zhí)行測(cè)試方法。它通過(guò)反射遍歷測(cè)試類中的方法,根據(jù)特定的注解(如@Test)識(shí)別出測(cè)試方法,并動(dòng)態(tài)調(diào)用這些方法來(lái)執(zhí)行測(cè)試。例如,在一個(gè)測(cè)試類中定義了多個(gè)測(cè)試方法,JUnit 通過(guò)反射獲取這些方法并依次執(zhí)行,從而實(shí)現(xiàn)對(duì)代碼的自動(dòng)化測(cè)試。

(2) 動(dòng)態(tài)代理的實(shí)際應(yīng)用

  • Spring AOP:Spring AOP 大量使用動(dòng)態(tài)代理來(lái)實(shí)現(xiàn)切面功能。例如,在一個(gè)企業(yè)級(jí)應(yīng)用中,可能需要對(duì)業(yè)務(wù)方法進(jìn)行日志記錄、事務(wù)管理等操作。通過(guò)動(dòng)態(tài)代理,可以在不修改目標(biāo)業(yè)務(wù)類代碼的前提下,為目標(biāo)方法添加這些額外的功能。Spring 會(huì)為目標(biāo)對(duì)象創(chuàng)建動(dòng)態(tài)代理對(duì)象,當(dāng)調(diào)用代理對(duì)象的方法時(shí),會(huì)先執(zhí)行切面邏輯(如記錄日志),然后再調(diào)用目標(biāo)對(duì)象的實(shí)際方法,最后還可以在方法調(diào)用后執(zhí)行一些清理或補(bǔ)充邏輯(如事務(wù)提交)。
  • 在數(shù)據(jù)庫(kù)事務(wù)管理中,動(dòng)態(tài)代理可以用于管理事務(wù)的開(kāi)啟、提交和回滾。以一個(gè)銀行轉(zhuǎn)賬操作的業(yè)務(wù)方法為例,動(dòng)態(tài)代理可以在方法調(diào)用前開(kāi)啟事務(wù),方法執(zhí)行過(guò)程中如果沒(méi)有異常則提交事務(wù),若出現(xiàn)異常則回滾事務(wù)。這樣可以將事務(wù)管理的邏輯從業(yè)務(wù)代碼中分離出來(lái),提高代碼的可維護(hù)性和復(fù)用性。

通過(guò)上面的例子可以初步了解反射與動(dòng)態(tài)代理,想要深度學(xué)習(xí)的話可以多看看框架中的源碼,學(xué)習(xí)優(yōu)秀的代碼風(fēng)格以及設(shè)計(jì)模式。

到此這篇關(guān)于JavaSE反射與動(dòng)態(tài)代理的文章就介紹到這了,更多相關(guān)JavaSE反射與動(dòng)態(tài)代理內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java使用XWPFDocument生成word文檔的示例代碼

    Java使用XWPFDocument生成word文檔的示例代碼

    XWPFDocument 是 Apache POI 庫(kù)中用于操作 .docx 格式 Word 文檔的核心類,本文將針對(duì) XWPFDocument 進(jìn)行詳細(xì)解析,涵蓋其核心功能、常見(jiàn)用法及實(shí)際開(kāi)發(fā)中的關(guān)鍵點(diǎn)
    2025-12-12
  • JavaEE微框架Spring Boot深入解讀

    JavaEE微框架Spring Boot深入解讀

    spring框架作為JavaEE框架領(lǐng)域的一款重要的開(kāi)源框架,在企業(yè)應(yīng)用開(kāi)發(fā)中有著很重要的作用。接下來(lái)通過(guò)本文給大家介紹JavaEE微框架Spring Boot深入解讀,需要的朋友可以參考下
    2017-04-04
  • Spring 父類變量注入失敗的解決

    Spring 父類變量注入失敗的解決

    這篇文章主要介紹了Spring 父類變量注入失敗的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • java實(shí)現(xiàn)2048小游戲(含注釋)

    java實(shí)現(xiàn)2048小游戲(含注釋)

    這篇文章主要為大家介紹了java實(shí)現(xiàn)2048小游戲,含詳細(xì)注釋,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-04-04
  • Rabbitmq消息推送功能實(shí)現(xiàn)示例

    Rabbitmq消息推送功能實(shí)現(xiàn)示例

    rabbitMQ為異步消息處理提出了一個(gè)很好的解決方案,它是一個(gè)非常好用的消息中間件。主要解決當(dāng)生產(chǎn)者大量產(chǎn)生數(shù)據(jù)時(shí),消費(fèi)者無(wú)法快速消費(fèi)的問(wèn)題。這個(gè)時(shí)候需要一個(gè)中間層,保存這個(gè)數(shù)據(jù),rabbitMQ是一個(gè)很好的解決方案
    2022-12-12
  • Java通過(guò)BCrypt加密過(guò)程詳解

    Java通過(guò)BCrypt加密過(guò)程詳解

    這篇文章主要介紹了Java通過(guò)BCrypt加密過(guò)程詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-07-07
  • JVM:晚期(運(yùn)行期)優(yōu)化的深入理解

    JVM:晚期(運(yùn)行期)優(yōu)化的深入理解

    今天小編就為大家分享一篇關(guān)于JVM:晚期(運(yùn)行期)優(yōu)化的深入理解,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧
    2019-02-02
  • 淺談String.split()遇到空字符串的幾種情況

    淺談String.split()遇到空字符串的幾種情況

    這篇文章主要介紹了淺談String.split()遇到空字符串的幾種情況,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-10-10
  • 一文徹底搞懂java多線程和線程池

    一文徹底搞懂java多線程和線程池

    當(dāng)一個(gè)服務(wù)器接受到大量短小線程的請(qǐng)求時(shí),使用線程池技術(shù)是非常合適的,它可以大大減少線程的創(chuàng)建和銷毀次數(shù),提高服務(wù)器的工作效率,這篇文章主要給大家介紹了如何通過(guò)一文徹底搞懂java多線程和線程池的相關(guān)資料,需要的朋友可以參考下
    2021-09-09
  • SpringBoot如何獲取application.properties中自定義的值

    SpringBoot如何獲取application.properties中自定義的值

    這篇文章主要介紹了SpringBoot獲取application.properties中的自定義的值,目錄結(jié)構(gòu)文件代碼給大家列舉的非常詳細(xì),需要的朋友可以參考下
    2021-09-09

最新評(píng)論

金川县| 论坛| 墨玉县| 克拉玛依市| 陆良县| 阜南县| 呈贡县| 博湖县| 棋牌| 白沙| 永善县| 南木林县| 桦南县| 绍兴市| 长兴县| 沛县| 高邑县| 浪卡子县| 漳平市| 二连浩特市| 农安县| 石泉县| 上饶市| 岱山县| 莱芜市| 新沂市| 思南县| 葫芦岛市| 略阳县| 营口市| 云南省| 石城县| 内丘县| 伊川县| 綦江县| 泰顺县| 白朗县| 昔阳县| 临清市| 泌阳县| 绥宁县|