Spring中的代理ProxyFactory解析
前言
當(dāng)涉及到Java程序員們談?wù)撁嫦驅(qū)ο缶幊痰臅r候,代理模式總是一個熱門話題。代理模式在許多場景下都有用武之地,比如日志記錄、事務(wù)管理、權(quán)限驗證等等。
而在Java中,代理模式的實現(xiàn)通常依靠Proxy類和InvocationHandler接口。本文將介紹如何使用ProxyFactory來創(chuàng)建代理模式。
什么是代理模式?
在計算機科學(xué)中,代理模式是一種結(jié)構(gòu)型設(shè)計模式,它可以為其他對象提供一個替代品或者占位符,以控制對這個對象的訪問。
代理對象通常充當(dāng)了客戶端和目標(biāo)對象之間的中介,從而可以隱藏目標(biāo)對象的實現(xiàn)細(xì)節(jié)、保護目標(biāo)對象不被非法訪問、增強目標(biāo)對象的功能等等。
代理模式有兩種形式:靜態(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;
}在代理模式中,當(dāng)我們調(diào)用代理對象的方法時,實際上會調(diào)用InvocationHandler的invoke()方法,在這個方法中,我們可以根據(jù)需要進行一些操作,并返回目標(biāo)對象的執(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)類接受一個代理對象的目標(biāo)對象,然后在代理方法被調(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)建目標(biāo)對象
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)建了一個目標(biāo)對象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)建目標(biāo)對象
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)文章
springboot /tmp 臨時目錄的具體實現(xiàn)
springboot應(yīng)用服務(wù)再啟動的時候,會在操作系統(tǒng)的/tmp目錄,本文主要介紹了springboot /tmp 臨時目錄的具體實現(xiàn),具有一定的參考價值,感興趣的可以了解一下2024-06-06
關(guān)于Spring?Validation數(shù)據(jù)校檢的使用流程分析
在實際項目中,對客戶端傳遞到服務(wù)端的參數(shù)進行校驗至關(guān)重要,SpringValidation提供了一種便捷的方式來實現(xiàn)這一需求,通過在POJO類的屬性上添加檢查注解,本文給大家介紹Spring?Validation數(shù)據(jù)校檢的使用流程,感興趣的朋友一起看看吧2024-11-11
淺談Java關(guān)閉線程池shutdown和shutdownNow的區(qū)別
本文主要介紹了Java關(guān)閉線程池shutdown和shutdownNow的區(qū)別,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-09-09
SpringBoot中的@EnableAutoConfiguration注解解析
這篇文章主要介紹了SpringBoot中的@EnableAutoConfiguration注解解析,@EnableAutoConfiguration也是借助@Import的幫助,將所有符合自動配置條件的bean定義注冊到IoC容器,需要的朋友可以參考下2023-09-09

