Java中通過反射實現(xiàn)代理Proxy代碼實例
1.實現(xiàn)一個簡易的代理類
java實現(xiàn)代理可以通過java.lang.reflect.Proxy接口結合java.lang.reflect.InvocationHandler來實現(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("預處理");
Object object = method.invoke(this.object, args);
if(object instanceof Person) {
((Person) object).setName("姓名:" + ((Person) object).getName());
}
System.out.println("后處理");
return object;
}
}通過如下方法調用生成代理的對象
public class Test {
public static void main(String[] args) {
ProxyHandler proxyHandler = new ProxyHandler(); //生成代理類初始化被代理類
UserService userService = proxyHandler.newProxyInstance(); //生成代理實例
System.out.println(userService.getUserInfo(1).getName()); //調用被代理方法
}
}此時代理類內自定義的invoke方法將會在被代理方法執(zhí)行前后執(zhí)行自定義的操作
控制臺輸出結果
預處理
后處理
姓名: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);//獲取到代理類的構造器
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});//生成代理類實例
} 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);
}
}從如上代碼可見,首先需要獲取代理類,然后再獲取到代理類構造器,最后使用構造器生成代理類實例。
關鍵的代理類獲取在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方法中,使用了關鍵的WeakCache類,其中的結構是ConcurrentMap<Object, ConcurrentMap<Object, Supplier<V>>>。 最外層map的key是通過classLoader得出的CacheKey類型,value是一個map,其中key為由classLoader和interfaces[]共同得出的一個Key,value是緩存的代理類。
到此這篇關于Java中通過反射實現(xiàn)代理Proxy代碼實例的文章就介紹到這了,更多相關Java反射實現(xiàn)代理內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
mybatis generator 配置 反向生成Entity簡單增刪改查(推薦)
這篇文章主要介紹了mybatis generator 配置 反向生成Entity簡單增刪改查(推薦)的相關資料,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2016-12-12
使用java?-Dloader.path=./lib?-jar啟動應用的完整實踐指南
java -Dloader.path="lib/" -jar XXXX.jar是一個用于啟動Java 應用程序的命令,這篇文章主要介紹了使用java?-Dloader.path=./lib?-jar啟動應用的完整實踐指南,文中給出了詳細代碼示例,需要的朋友可以參考下2025-10-10
Kotlin 語言中調用 JavaScript 方法實例詳解
這篇文章主要介紹了Kotlin 語言中調用 JavaScript 方法實例詳解的相關資料,需要的朋友可以參考下2017-06-06
解決springboot?druid數(shù)據(jù)庫連接池連接失敗后一直重連問題
這篇文章主要介紹了解決springboot?druid數(shù)據(jù)庫連接池連接失敗后一直重連問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-11-11
SpringBoot內置服務器(Tomcat/Jetty/Undertow)切換的操作指南
本文介紹了如何在SpringBoot中切換內置服務器(Tomcat、Jetty和Undertow),分析了它們的核心差異和適用場景,通過修改pom.xml和application.yml文件,可以實現(xiàn)服務器的切換和自定義配置,最后給出了選型建議和注意事項,需要的朋友可以參考下2026-03-03
spring boot中的properties參數(shù)配置詳解
這篇文章主要介紹了spring boot中的properties參數(shù)配置,需要的朋友可以參考下2017-09-09

