Java中通過反射實(shí)現(xiàn)代理Proxy代碼實(shí)例
1.實(shí)現(xiàn)一個(gè)簡易的代理類
java實(shí)現(xiàn)代理可以通過java.lang.reflect.Proxy接口結(jié)合java.lang.reflect.InvocationHandler來實(shí)現(xiàn)
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class ProxyHandler implements InvocationHandler {
private UserService object;
public ProxyHandler() {
this.object = new UserServiceImpl();
}
public UserService newProxyInstance(){
return (UserService) Proxy.newProxyInstance(this.object.getClass().getClassLoader(), this.object.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("預(yù)處理");
Object object = method.invoke(this.object, args);
if(object instanceof Person) {
((Person) object).setName("姓名:" + ((Person) object).getName());
}
System.out.println("后處理");
return object;
}
}通過如下方法調(diào)用生成代理的對象
public class Test {
public static void main(String[] args) {
ProxyHandler proxyHandler = new ProxyHandler(); //生成代理類初始化被代理類
UserService userService = proxyHandler.newProxyInstance(); //生成代理實(shí)例
System.out.println(userService.getUserInfo(1).getName()); //調(diào)用被代理方法
}
}此時(shí)代理類內(nèi)自定義的invoke方法將會(huì)在被代理方法執(zhí)行前后執(zhí)行自定義的操作
控制臺輸出結(jié)果
預(yù)處理
后處理
姓名:libiyi
2.Proxy.newProxyInstance()解析
如下是源碼
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
Objects.requireNonNull(h);
final Class<?>[] intfs = interfaces.clone();
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
}
/*
* 從緩存中獲取到代理類
*/
Class<?> cl = getProxyClass0(loader, intfs);
try {
if (sm != null) {
checkNewProxyPermission(Reflection.getCallerClass(), cl);
}
final Constructor<?> cons = cl.getConstructor(constructorParams);//獲取到代理類的構(gòu)造器
final InvocationHandler ih = h;
if (!Modifier.isPublic(cl.getModifiers())) {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
cons.setAccessible(true);
return null;
}
});
}
return cons.newInstance(new Object[]{h});//生成代理類實(shí)例
} catch (IllegalAccessException|InstantiationException e) {
throw new InternalError(e.toString(), e);
} catch (InvocationTargetException e) {
Throwable t = e.getCause();
if (t instanceof RuntimeException) {
throw (RuntimeException) t;
} else {
throw new InternalError(t.toString(), t);
}
} catch (NoSuchMethodException e) {
throw new InternalError(e.toString(), e);
}
}從如上代碼可見,首先需要獲取代理類,然后再獲取到代理類構(gòu)造器,最后使用構(gòu)造器生成代理類實(shí)例。
關(guān)鍵的代理類獲取在getProxyClass0方法、和getConstructor中
private static Class<?> getProxyClass0(ClassLoader loader,
Class<?>... interfaces) {
if (interfaces.length > 65535) {
throw new IllegalArgumentException("interface limit exceeded");
}
// If the proxy class defined by the given loader implementing
// the given interfaces exists, this will simply return the cached copy;
// otherwise, it will create the proxy class via the ProxyClassFactory
return proxyClassCache.get(loader, interfaces);
}
private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());在getProxyClass0方法中,使用了關(guān)鍵的WeakCache類,其中的結(jié)構(gòu)是ConcurrentMap<Object, ConcurrentMap<Object, Supplier<V>>>。 最外層map的key是通過classLoader得出的CacheKey類型,value是一個(gè)map,其中key為由classLoader和interfaces[]共同得出的一個(gè)Key,value是緩存的代理類。
到此這篇關(guān)于Java中通過反射實(shí)現(xiàn)代理Proxy代碼實(shí)例的文章就介紹到這了,更多相關(guān)Java反射實(shí)現(xiàn)代理內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java設(shè)計(jì)模式之Prototype原型模式
這篇文章主要為大家詳細(xì)介紹了Java設(shè)計(jì)模式之Prototype原型模式的相關(guān)資料,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-03-03
詳解eclipse中Maven工程使用Tomcat7以上插件的方法
本篇文章主要介紹了詳解eclipse中Maven工程使用Tomcat7以上插件的方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-12-12
SpringCloud gateway如何修改返回?cái)?shù)據(jù)
這篇文章主要介紹了SpringCloud gateway如何修改返回?cái)?shù)據(jù)的操作,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-06-06
解決引用slf4j中Logger.info只打印出文字沒有數(shù)據(jù)的問題
這篇文章主要介紹了解決引用slf4j中Logger.info只打印出文字沒有數(shù)據(jù)的問題,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12
深入解析StringBuffer和StringBuilder的區(qū)別
以下是對java中StringBuffer與StringBuilder的區(qū)別進(jìn)行了詳細(xì)的分析介紹,需要的朋友可以參考下2013-07-07
Java使用freemarker實(shí)現(xiàn)word下載方式
文章介紹了如何使用FreeMarker實(shí)現(xiàn)Word文件下載,包括引用依賴、創(chuàng)建Word模板、將Word文件存為XML格式、更改后綴為FTL模板、處理圖片和代碼實(shí)現(xiàn)2025-02-02
JAVA實(shí)現(xiàn)DOC轉(zhuǎn)PDF的示例代碼
Word作為目前主流的文本編輯軟件之一,功能十分強(qiáng)大,但是在傳輸?shù)臅r(shí)候不穩(wěn)定,那么如何從DOC轉(zhuǎn)PDF,本文就來介紹一下,感興趣的可以了解一下2021-08-08
SpringBoot?mybatis-plus使用json字段實(shí)戰(zhàn)指南
在現(xiàn)代應(yīng)用開發(fā)中經(jīng)常會(huì)使用JSON格式存儲和傳輸數(shù)據(jù),為了便捷地處理數(shù)據(jù)庫中的JSON字段,MyBatis-Plus提供了強(qiáng)大的JSON處理器,這篇文章主要給大家介紹了關(guān)于SpringBoot?mybatis-plus使用json字段的相關(guān)資料,需要的朋友可以參考下2024-01-01

