Spring中的代理ProxyFactory解析
前言
當涉及到Java程序員們談?wù)撁嫦驅(qū)ο缶幊痰臅r候,代理模式總是一個熱門話題。代理模式在許多場景下都有用武之地,比如日志記錄、事務(wù)管理、權(quán)限驗證等等。
而在Java中,代理模式的實現(xiàn)通常依靠Proxy類和InvocationHandler接口。本文將介紹如何使用ProxyFactory來創(chuàng)建代理模式。
什么是代理模式?
在計算機科學(xué)中,代理模式是一種結(jié)構(gòu)型設(shè)計模式,它可以為其他對象提供一個替代品或者占位符,以控制對這個對象的訪問。
代理對象通常充當了客戶端和目標對象之間的中介,從而可以隱藏目標對象的實現(xiàn)細節(jié)、保護目標對象不被非法訪問、增強目標對象的功能等等。
代理模式有兩種形式:靜態(tài)代理和動態(tài)代理。靜態(tài)代理的優(yōu)點是能夠提前做好一些工作,例如參數(shù)的檢查、日志記錄等等;
缺點則是需要針對每個需要代理的接口編寫一個代理類。而動態(tài)代理則可以根據(jù)接口生成代理對象,并且可以在運行時動態(tài)的添加和修改代理方法,因此更加靈活。
了解Proxy和InvocationHandler
在Java中,代理模式的實現(xiàn)主要依靠了Proxy類和InvocationHandler接口。其中,Proxy類是生成代理類的主要工具,而InvocationHandler則是提供對代理方法的具體實現(xiàn)。
Proxy類有兩個靜態(tài)方法可以用來創(chuàng)建代理對象:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
該方法用于創(chuàng)建一個動態(tài)代理對象,參數(shù)loader表示ClassLoader、interfaces表示實現(xiàn)的接口列表、h表示InvocationHandler。
public static Object newProxyInstance(Class<?> clazz, InvocationHandler h)
該方法用于創(chuàng)建一個指定類的代理對象,參數(shù)clazz表示需要代理的類、h表示InvocationHandler。
而InvocationHandler接口則是定義了一個統(tǒng)一的代理方法:
public interface InvocationHandler { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable; }
在代理模式中,當我們調(diào)用代理對象的方法時,實際上會調(diào)用InvocationHandler的invoke()方法,在這個方法中,我們可以根據(jù)需要進行一些操作,并返回目標對象的執(zhí)行結(jié)果。
使用ProxyFactory創(chuàng)建動態(tài)代理
在Java中,如果要使用動態(tài)代理,首先需要創(chuàng)建一個InvocationHandler實現(xiàn)類。例如,下面是一個簡單的InvocationHandler實現(xiàn)類:
public class MyInvocationHandler implements InvocationHandler { private Object target; public MyInvocationHandler(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("Before calling " + method.getName()); Object result = method.invoke(target, args); System.out.println("After calling " + method.getName()); return result; } }
這個InvocationHandler實現(xiàn)類接受一個代理對象的目標對象,然后在代理方法被調(diào)用前輸出一行日志,在返回結(jié)果之前再輸出一行日志。
然后我們可以通過ProxyFactory來創(chuàng)建一個動態(tài)代理對象。ProxyFactory是一個通用的代理工廠,它提供了很多便捷的方法來創(chuàng)建不同類型的代理。例如下面的代碼演示了如何使用ProxyFactory來創(chuàng)建一個JDK動態(tài)代理:
public class ProxyTest { public static void main(String[] args) { // 創(chuàng)建目標對象 HelloService helloService = new HelloServiceImpl(); // 創(chuàng)建InvocationHandler實例 InvocationHandler invocationHandler = new MyInvocationHandler(helloService); // 創(chuàng)建代理對象 HelloService proxy = (HelloService) ProxyFactory.getProxy(helloService.getClass, invocationHandler); // 調(diào)用代理對象的方法 proxy.sayHello("Jack"); } }
在上面的代碼中,我們首先創(chuàng)建了一個目標對象HelloServiceImpl。然后創(chuàng)建了一個InvocationHandler實例,并將HelloServiceImpl作為它的參數(shù)傳遞進去。最后通過調(diào)用ProxyFactory的getProxy()方法來生成一個動態(tài)代理對象proxy。在調(diào)用proxy的sayHello()方法時,實際上會調(diào)用MyInvocationHandler的invoke()方法,在這個方法中輸出日志并調(diào)用HelloServiceImpl的sayHello()方法,最終返回結(jié)果。
使用ProxyFactory創(chuàng)建Cglib動態(tài)代理
除了JDK動態(tài)代理之外,還有一種常見的動態(tài)代理實現(xiàn)方式是使用Cglib庫。與JDK動態(tài)代理不同,Cglib動態(tài)代理可以代理非接口類型的類。
下面我們演示如何使用ProxyFactory來創(chuàng)建一個Cglib動態(tài)代理:
public class ProxyTest { public static void main(String[] args) { // 創(chuàng)建目標對象 UserDaoImpl userDao = new UserDaoImpl(); // 創(chuàng)建MethodInterceptor實例 MethodInterceptor methodInterceptor = new MyMethodInterceptor(userDao); // 創(chuàng)建代理對象 UserDaoImpl proxy = (UserDaoImpl) ProxyFactory.getProxy(userDao.getClass(), methodInterceptor); // 調(diào)用代理對象的方法 proxy.save(); } } class UserDaoImpl { public void save() { System.out.println("Saving user..."); } } class MyMethodInterceptor implements MethodInterceptor { private Object target; public MyMethodInterceptor(Object target) { this.target = target; } @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("Before calling " + method.getName()); Object result = method.invoke(target, args); System.out.println("After calling " + method.getName()); return result; } }
在這個例子中,我們創(chuàng)建了一個UserDaoImpl類,并為它創(chuàng)建了一個MethodInterceptor實現(xiàn)類。
然后通過調(diào)用ProxyFactory的getProxy()方法來生成一個Cglib動態(tài)代理對象proxy。
在調(diào)用proxy的save()方法時,實際上會調(diào)用MyMethodInterceptor的intercept()方法,在這個方法中輸出日志并調(diào)用UserDaoImpl的save()方法,最終返回結(jié)果。
總結(jié)
本文介紹了如何使用ProxyFactory來創(chuàng)建動態(tài)代理,包括JDK動態(tài)代理和Cglib動態(tài)代理。
通過使用ProxyFactory,可以更加方便地創(chuàng)建代理對象,并且可以根據(jù)需要自定義不同類型的代理行為。
雖然動態(tài)代理不是解決所有問題的萬能工具,但在某些場景下,它仍然是一種非常強大和有用的設(shè)計模式。
到此這篇關(guān)于Spring中的代理ProxyFactory解析的文章就介紹到這了,更多相關(guān)Spring的ProxyFactory內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java結(jié)合Kotlin實現(xiàn)寶寶年齡計算
這篇文章主要為大家介紹了Java結(jié)合Kotlin實現(xiàn)寶寶年齡計算示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-06-06本地MinIO存儲服務(wù)Java遠程調(diào)用上傳文件的操作過程
MinIO是一款高性能、分布式的對象存儲系統(tǒng),它可以100%的運行在標準硬件上,即X86等低成本機器也能夠很好的運行MinIO,這篇文章主要介紹了本地MinIO存儲服務(wù)Java遠程調(diào)用上傳文件的操作過程,需要的朋友可以參考下2023-11-11IDEA 2020.2 +Gradle 6.6.1 + Spring Boot 2.3.4 創(chuàng)建多模塊項目的超詳細教程
這篇文章主要介紹了IDEA 2020.2 +Gradle 6.6.1 + Spring Boot 2.3.4 創(chuàng)建多模塊項目的教程,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-09-09SpringMVC+MyBatis 事務(wù)管理(實例)
本文先分析編程式注解事務(wù)和基于注解的聲明式事務(wù)。對SpringMVC+MyBatis 事務(wù)管理的相關(guān)知識感興趣的朋友一起學(xué)習(xí)吧2017-08-08RestTemplate使用Proxy代理作為跳板發(fā)送請求
這篇文章主要為大家介紹了RestTemplate使用代理proxy作為跳板發(fā)送請求的方法示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步2022-03-03Spring boot @RequestBody數(shù)據(jù)傳遞過程詳解
這篇文章主要介紹了Spring boot @RequestBody數(shù)據(jù)傳遞過程詳解,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2019-12-12如何手動安裝Gradle并配置IDEA使用Gradle構(gòu)建
本文給大家分享手動安裝Gradle并配置IDEA使用Gradle構(gòu)建的步驟,本文給大家介紹的非常詳細,感興趣的朋友一起看看吧2025-04-04Java?Collection接口中的常用方法總結(jié)
這篇文章將大概用代碼案例簡單總結(jié)一下?Collection?接口中的一些方法,我們會以他的實現(xiàn)類?Arraylist?為例創(chuàng)建對象。快一起來看看吧2022-12-12