Java中通過(guò)反射實(shí)現(xiàn)代理Proxy代碼實(shí)例
1.實(shí)現(xiàn)一個(gè)簡(jiǎn)易的代理類(lèi)
java實(shí)現(xiàn)代理可以通過(guò)java.lang.reflect.Proxy接口結(jié)合java.lang.reflect.InvocationHandler來(lái)實(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; } }
通過(guò)如下方法調(diào)用生成代理的對(duì)象
public class Test { public static void main(String[] args) { ProxyHandler proxyHandler = new ProxyHandler(); //生成代理類(lèi)初始化被代理類(lèi) UserService userService = proxyHandler.newProxyInstance(); //生成代理實(shí)例 System.out.println(userService.getUserInfo(1).getName()); //調(diào)用被代理方法 } }
此時(shí)代理類(lèi)內(nèi)自定義的invoke方法將會(huì)在被代理方法執(zhí)行前后執(zhí)行自定義的操作
控制臺(tái)輸出結(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); } /* * 從緩存中獲取到代理類(lèi) */ Class<?> cl = getProxyClass0(loader, intfs); try { if (sm != null) { checkNewProxyPermission(Reflection.getCallerClass(), cl); } final Constructor<?> cons = cl.getConstructor(constructorParams);//獲取到代理類(lèi)的構(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});//生成代理類(lèi)實(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); } }
從如上代碼可見(jiàn),首先需要獲取代理類(lèi),然后再獲取到代理類(lèi)構(gòu)造器,最后使用構(gòu)造器生成代理類(lèi)實(shí)例。
關(guān)鍵的代理類(lèi)獲取在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類(lèi),其中的結(jié)構(gòu)是ConcurrentMap<Object, ConcurrentMap<Object, Supplier<V>>>。 最外層map的key是通過(guò)classLoader得出的CacheKey類(lèi)型,value是一個(gè)map,其中key為由classLoader和interfaces[]共同得出的一個(gè)Key,value是緩存的代理類(lèi)。
到此這篇關(guān)于Java中通過(guò)反射實(shí)現(xiàn)代理Proxy代碼實(shí)例的文章就介紹到這了,更多相關(guān)Java反射實(shí)現(xiàn)代理內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(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以上插件的方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-12-12SpringCloud gateway如何修改返回?cái)?shù)據(jù)
這篇文章主要介紹了SpringCloud gateway如何修改返回?cái)?shù)據(jù)的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-06-06解決引用slf4j中Logger.info只打印出文字沒(méi)有數(shù)據(jù)的問(wèn)題
這篇文章主要介紹了解決引用slf4j中Logger.info只打印出文字沒(méi)有數(shù)據(jù)的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12深入解析StringBuffer和StringBuilder的區(qū)別
以下是對(duì)java中StringBuffer與StringBuilder的區(qū)別進(jìn)行了詳細(xì)的分析介紹,需要的朋友可以參考下2013-07-07Java使用freemarker實(shí)現(xiàn)word下載方式
文章介紹了如何使用FreeMarker實(shí)現(xiàn)Word文件下載,包括引用依賴、創(chuàng)建Word模板、將Word文件存為XML格式、更改后綴為FTL模板、處理圖片和代碼實(shí)現(xiàn)2025-02-02JAVA實(shí)現(xiàn)DOC轉(zhuǎn)PDF的示例代碼
Word作為目前主流的文本編輯軟件之一,功能十分強(qiáng)大,但是在傳輸?shù)臅r(shí)候不穩(wěn)定,那么如何從DOC轉(zhuǎn)PDF,本文就來(lái)介紹一下,感興趣的可以了解一下2021-08-08SpringBoot?mybatis-plus使用json字段實(shí)戰(zhàn)指南
在現(xiàn)代應(yīng)用開(kāi)發(fā)中經(jīng)常會(huì)使用JSON格式存儲(chǔ)和傳輸數(shù)據(jù),為了便捷地處理數(shù)據(jù)庫(kù)中的JSON字段,MyBatis-Plus提供了強(qiáng)大的JSON處理器,這篇文章主要給大家介紹了關(guān)于SpringBoot?mybatis-plus使用json字段的相關(guān)資料,需要的朋友可以參考下2024-01-01