java動態(tài)代理主要是有Proxy和InvocationHandler兩個類實現(xiàn)的
一、我先來看下如何使用Proxy和InvocationHandler來實現(xiàn)動態(tài)代理
1.先定義一個接口MarkMan
-
再定義的一個類MarkManFactory實現(xiàn)MarkMan
image.png -
然后定義一個MyInvocationHandler實現(xiàn)InvocationHandler。
在里面定義一個setFactory(Object obj)方法把要代理的對象傳入進去误堡,然后定義個newProxyInstance方法,方法里面調用Proxy.newProxyInstance()方法獲取代理對象奸绷。
實現(xiàn)InvocationHandler的invoke方法
image.png
4.然后在main方法中進行調用
image.png
我們運行下程序设捐,結果打壓如下
image.png
二借浊、通過調試模式我們發(fā)現(xiàn),動態(tài)代理里萝招,代理類的類名是這樣的:
[圖片上傳失敗...(image-9e5ea5-1613977035476)]
這個代理類為何是這個名字蚂斤?它是如何執(zhí)行被代理對象的相關方法呢?我們在java文件編譯后的目錄里其實找不到這個名為$Proxy0的class文件的槐沼。帶著這個問題我來看看Proxy和InvocationHandler的源碼 看它們是如何實現(xiàn)動態(tài)代理的
查看Proxy的newProxyInstance方法源碼
@CallerSensitive
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException {
Objects.requireNonNull(h);
........
/*
* Look up or generate the designated proxy class.
*/
//獲取clazz對象
Class<?> cl = getProxyClass0(loader, intfs);
/*
* Invoke its constructor with the designated invocation handler.
*/
try {
if (sm != null) {
checkNewProxyPermission(Reflection.getCallerClass(), cl);
}
//獲取構造函數(shù)
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;
}
});
}
//通過構造函數(shù)new一個實例對象
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);
}
}
通過源碼我們可以看到是newProxyInstance是通過獲取class對象,然后通過class對象獲取構造函數(shù),通過構造函數(shù)new一個實例對象返回 接下來我們看下getProxyClass0(loader, intfs)方法
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);
}
通過源碼 我們發(fā)現(xiàn)getProxyClass0就是從緩存中去獲取,繼續(xù)看WeakCache的get方法
這里我們主要看下subKeyFactory.apply(key, parameter)方法 ,其余都是驗證跟判斷
public V get(K key, P parameter) {
....省略
Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
Supplier<V> supplier = valuesMap.get(subKey);
Factory factory = null;
while (true) {
if (supplier != null) {
V value = supplier.get();
if (value != null) {
return value;
}
}
if (factory == null) {
factory = new Factory(key, parameter, subKey, valuesMap);
}
if (supplier == null) {
supplier = valuesMap.putIfAbsent(subKey, factory);
if (supplier == null) {
supplier = factory;
}
} else {
if (valuesMap.replace(subKey, supplier, factory)) {
supplier = factory;
} else {
// retry with current supplier
supplier = valuesMap.get(subKey);
}
}
}
}
subKeyFactory是BiFunction接口,通過查看實現(xiàn)類發(fā)現(xiàn)是ProxyClassFactory類,接下來看ProxyClassFactory 的apply方法
public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
....省略
String proxyPkg = null; // package to define proxy class in
int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
long num = nextUniqueNumber.getAndIncrement();
** //代理類的名稱 這里就是我們的要找的答案 $Proxy0 **
String proxyName = proxyPkg + proxyClassNamePrefix + num;
/*
* Generate the specified proxy class.
*/
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces, accessFlags);
try {
return defineClass0(loader, proxyName,
proxyClassFile, 0, proxyClassFile.length);
} catch (ClassFormatError e) {
throw new IllegalArgumentException(e.toString());
}
}
通過源碼我們發(fā)現(xiàn)通過ProxyGenerator.generateProxyClass( proxyName, interfaces, accessFlags) 轉換成byte[]數(shù)組,然后通過defineClass0方法轉換成Class字節(jié)碼返回,
public static byte[] generateProxyClass(final String var0, Class<?>[] var1, int var2) {
ProxyGenerator var3 = new ProxyGenerator(var0, var1, var2);
final byte[] var4 = var3.generateClassFile();
if (saveGeneratedFiles) {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
try {
int var1 = var0.lastIndexOf(46);
Path var2;
if (var1 > 0) {
Path var3 = Paths.get(var0.substring(0, var1).replace('.', File.separatorChar));
Files.createDirectories(var3);
var2 = var3.resolve(var0.substring(var1 + 1, var0.length()) + ".class");
} else {
var2 = Paths.get(var0 + ".class");
}
Files.write(var2, var4, new OpenOption[0]);
return null;
} catch (IOException var4x) {
throw new InternalError("I/O exception saving generated file: " + var4x);
}
}
});
}
return var4;
}
//本地方法
private static native Class<?> defineClass0(ClassLoader loader, String name,
byte[] b, int off, int len);
為了查看byte[]數(shù)組里面的內(nèi)容我們可以自己定義個ProxyUtils工具類把byte[]寫到文件中,查看里面的內(nèi)容
public class ProxyUtils {
public static void generateClassFile(Class clazz,String proxyName){
/*ProxyGenerator.generateProxyClass(
proxyName, interfaces, accessFlags);*/
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, new Class[]{clazz});
String paths = clazz.getResource(".").getPath();
System.out.println(paths);
FileOutputStream out = null;
try {
out = new FileOutputStream(paths+proxyName+".class");
out.write(proxyClassFile);
out.flush();
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
運行代碼 我看到生成的文件是以Proxy1這么的名稱
查看里面的內(nèi)容
public final class $Proxy0 extends Proxy implements Person
{
private static Method m1;
private static Method m2;
private static Method m3;
private static Method m0;
/**
*注意這里是生成代理類的構造方法,方法參數(shù)為InvocationHandler類型岗钩,看到這纽窟,是不是就有點明白
*為何代理對象調用方法都是執(zhí)行InvocationHandler中的invoke方法,而InvocationHandler又持有一個
*被代理對象的實例兼吓,不禁會想難道是....臂港? 沒錯,就是你想的那樣视搏。
*
*super(paramInvocationHandler)审孽,是調用父類Proxy的構造方法。
*父類持有:protected InvocationHandler h;
*Proxy構造方法:
* protected Proxy(InvocationHandler h) {
* Objects.requireNonNull(h);
* this.h = h;
* }
*
*/
public $Proxy0(InvocationHandler paramInvocationHandler) throws {
super(paramInvocationHandler);
}
//這個靜態(tài)塊本來是在最后的浑娜,我把它拿到前面來佑力,方便描述
static{
try {
//看看這兒靜態(tài)塊兒里面有什么,是不是找到了saleMan方法筋遭。請記住saleMan通過反射得到的名字m3打颤,其他的先不管
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] {
Class.forName("java.lang.Object") });
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
m3 = Class.forName("proxy.MarkManFactory").getMethod("saleMan", new Class[0]);
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
return;
} catch (NoSuchMethodException localNoSuchMethodException){
throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
}catch (ClassNotFoundException localClassNotFoundException){
throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
}
}
/**
*
*這里調用代理對象的saleMan方法,直接就調用了InvocationHandler中的invoke方法漓滔,并把m3傳了進去瘸洛。
*this.h.invoke(this, m3, null);這里簡單,明了次和。
*來,再想想那伐,代理對象持有一個InvocationHandler對象踏施,InvocationHandler對象持有一個被代理的對象,
*再聯(lián)系到InvacationHandler中的invoke方法罕邀。嗯畅形,就是這樣。
*/
public final void saleMan() throws {
try {
this.h.invoke(this, m3, null);
return;
}catch (Error|RuntimeException localError){
throw localError;
}catch (Throwable localThrowable){
throw new UndeclaredThrowableException(localThrowable);
}
}
//注意诉探,這里為了節(jié)省篇幅日熬,省去了toString,hashCode肾胯、equals方法的內(nèi)容竖席。原理和saleMan方法一毛一樣耘纱。
}
這的h是什么呢 我們看下Proxy類可以看到
這個h的實例來自哪里?不就是我們在創(chuàng)建代理類的實例時傳入的嗎毕荐?
到此整個動態(tài)代理的源碼分析就結束了