Java的三種代理模式&完整源碼分析
參考資料:
[博客園-WeakCache緩存的實現機制](https://www.cnblogs.com/liuyun1995/p/8144676.html)
靜態代理
靜態代理在使用時,需要定義接口或者父類,被代理對象與代理對象一起實現相同的接口或者是繼承相同父類
- 可以做到在不修改目標對象的功能前提下,對目標功能擴展
- 缺點:
- 因為代理對象需要與目標對象實現一樣的接口,所以會有很多代理類,類太多
- 同時,一旦接口增加方法,目標對象與代理對象都要維護
如何解決靜態代理中的缺點呢?答案是可以使用動態代理方式
實現靜態代理的步驟
- 定義業務接口
- 被代理類實現業務接口
- 定義代理類並實現業務接口
- 最后便可通過客戶端進行調用(這里可以理解成程序的main方法里的內容)
定義接口 UserInterface
public interface UserInterface {
// 保存用戶信息
void save();
}
定義接口的實現類 UserService
public class UserService implements UserInterface {
@Override
public void save() {
System.out.println("[靜態代理] 保存用戶信息");
}
}
定義靜態代理 UserProxy
public class UserProxy implements UserInterface {
private UserInterface userInterface;
public UserProxy(UserInterface userInterface) {
this.userInterface = userInterface;
}
/**
* save 代理方法
*/
@Override
public void save() {
// 調用目標方法前處理
System.out.println("[靜態代理] save 開始代理...");
// 調用目標方法
userInterface.save();
// 調用目標方法后處理
System.out.println("[靜態代理] save 結束代理...");
}
}
測試客戶端
public class Client {
public static void main(String[] args) {
// 新建目標對象
UserService userService = new UserService();
// 創建目標對象的代理對象
UserProxy userProxy = new UserProxy(userService);
// 執行代理對象
userProxy.save();
}
}
動態代理
Java動態代理的優勢是實現無侵入式的代碼擴展,也就是方法的增強;讓你可以在不用修改源碼的情況下,增強一些方法;在方法的前后你可以做你任何想做的事情(甚至不去執行這個方法就可以)
特點
- 在程序運行時,通過反射機制動態生成
- 動態代理類通常代理接口下的所有類
- 動態代理事先不知道要代理的是什么,只有在運行的時候才能確定
JDK動態代理
- 動態代理的調用處理程序必須事先InvocationHandler接口,及使用Proxy類中的newProxyInstance方法動態的創建代理類
- Java動態代理只能代理接口,要代理類需要使用第三方的CLIGB等類庫
問題
- 為什么JDK動態代理只能代理接口?
Proxy.java->ProxyClassFactory->apply();
/*
* Verify that the Class object actually represents an
* interface.
*/
// interfaceClass 指的是 Proxy.newProxyInstance 中的 interfaces
if (!interfaceClass.isInterface()) {
throw new IllegalArgumentException(
interfaceClass.getName() + " is not an interface");
}
注意該方法是在Proxy類中是靜態方法,且接收的三個參數依次為:
ClassLoader loader:指定當前目標對象使用類加載器,獲取加載器的方法是固定的Class<?>[] interfaces:目標對象實現的接口的類型,使用泛型方式確認類型InvocationHandler h:事件處理,執行目標對象的方法時,會觸發事件處理器的方法,會把當前執行目標對象的方法作為參數傳入
實現JDK動態代理的步驟
- 創建被代理的接口和類
- 創建InvocationHandler接口的實現類,在invoke方法中實現代理邏輯
- 通過Proxy的靜態方法
newProxyInstance( ClassLoaderloader, Class[] interfaces, InvocationHandler h)創建一個代理對象 - 使用代理對象
定義接口 UserInterface
public interface UserInterface {
// 保存用戶信息
void save();
// 更新用戶信息
void update();
}
定義接口的實現類 UserService
public class UserService implements UserInterface {
@Override
public void save() {
System.out.println("[JDK動態代理] 保存用戶信息");
}
@Override
public void update() {
System.out.println("[JDK動態代理] 更新用戶信息");
}
}
定義代理工廠 ProxyFactory
public class ProxyFactory {
// 維護的目標對象
private Object target;
private Class<?> clazz;
public ProxyFactory(Object target, Class<?> clazz) {
this.target = target;
this.clazz = clazz;
}
// 獲取代理對象
public Object getProxyObjectByClazz() {
return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
new Class[]{clazz},
(proxy, method, args) -> {
System.out.println("[JDK動態代理] save 開始代理...");
System.out.println("當前線程名稱:" + Thread.currentThread().getName());
String className = method.getDeclaringClass().getName();
System.out.println("目標對象類名稱:" + className);
String methodName = method.getName();
System.out.println("目標對象方法名:" + methodName);
Class<?>[] parameterTypes = method.getParameterTypes();
System.out.println("目標對象參數:" + parameterTypes);
// 執行目標對象並獲取返回值/該方法后面不會執行
// Object returnValue = method.invoke(target, args);
System.out.println("[JDK動態代理] save 結束代理...");
return null;
});
}
/**
* 獲取代理對象
*
* @return
*/
public Object getProxyObjectByTarget() {
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
(proxy, method, args) -> {
System.out.println("[JDK動態代理] save 開始代理...");
System.out.println("當前線程名稱:" + Thread.currentThread().getName());
String className = method.getDeclaringClass().getName();
System.out.println("目標對象類名稱:" + className);
String methodName = method.getName();
System.out.println("目標對象方法名:" + methodName);
Class<?>[] parameterTypes = method.getParameterTypes();
System.out.println("目標對象參數:" + parameterTypes);
// 執行目標對象並獲取返回值
Object returnValue = method.invoke(target, args);
System.out.println("[JDK動態代理] save 結束代理...");
return returnValue;
});
}
}
測試客戶端
public class Client {
public static void main(String[] args) {
System.out.println("********************* 使用接口生成代理對象 *********************");
System.out.println("當前線程:" + Thread.currentThread().getName());
UserInterface proxy = (UserInterface) new ProxyFactory(null, UserInterface.class).getProxyObjectByClazz();
System.out.println("代理對象類型:" + proxy.getClass());
proxy.save();
System.out.println("********************* 使用實現類生成代理對象 *********************");
UserService userService = new UserService();
System.out.println("目標對象類型:" + userService.getClass());
UserInterface proxy2 = (UserInterface) new ProxyFactory(userService, null).getProxyObjectByTarget();
System.out.println("代理對象類型:" + proxy2.getClass());
proxy2.update();
}
}
輸出結果
********************* 使用接口生成代理對象 *********************
當前線程:main
代理對象類型:class com.sun.proxy.$Proxy0
[JDK動態代理] save 開始代理...
當前線程名稱:main
目標對象類名稱:com.example.spring_boot.modules.study.proxyobject.jdkproxy.UserInterface
目標對象方法名:save
目標對象參數:[Ljava.lang.Class;@c038203
[JDK動態代理] save 結束代理...
********************* 使用實現類生成代理對象 *********************
目標對象類型:class com.example.spring_boot.modules.study.proxyobject.jdkproxy.UserService
代理對象類型:class com.sun.proxy.$Proxy0
[JDK動態代理] save 開始代理...
當前線程名稱:main
目標對象類名稱:com.example.spring_boot.modules.study.proxyobject.jdkproxy.UserInterface
目標對象方法名:update
目標對象參數:[Ljava.lang.Class;@cb5822
[JDK動態代理] 更新用戶信息
[JDK動態代理] save 結束代理...
運行結果和靜態代理一樣,說明成功了。但是,我們注意到,我們並沒有像靜態代理那樣去自己定義一個代理類,並實例化代理對象。實際上,動態代理的代理對象是在內存中的,是JDK根據我們傳入的參數生成好的。那動態代理的代理類和代理對象是怎么產生的呢?重頭戲來了,且往下看
JDK動態代理源碼分析
代理對象的入口
Proxy.java->newProxyInstance();
// 1. 查找或生成指定的代理類(下面會詳細說明該部分內容)
Class<?> cl = getProxyClass0(loader, intfs);
// 2. 根據Class獲取構造器
final Constructor<?> cons = cl.getConstructor(constructorParams);
// 3. 返回實例化的構造器
return cons.newInstance(new Object[]{h});
詳細說說 getProxyClass0 這個方法
private static Class<?> getProxyClass0(ClassLoader loader,
Class<?>... interfaces) {
// 限定代理的接口不能超過65535個
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
// 如果給定加載程序定義的代理類實現
// 給定的接口存在,這只會返回緩存的副本;
// 否則,它將通過proxyclassfactory創建代理類
return proxyClassCache.get(loader, interfaces);
}
說明一下上面提到的 proxyClassCache
// proxyClassCache變量是在Proxy.java中的靜態變量
// 一個靜態的 proxy class 緩存對象
private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
/* 那就再探究一下 WeakCache 這個類 */
final class WeakCache<K, P, V> {
// Reference引用隊列
private final ReferenceQueue<K> refQueue = new ReferenceQueue<>();
// the key type is Object for supporting null key
// 使用了二級緩存技術,key為一級緩存,value為二級緩存,key是Object類型是為了存儲null
private final ConcurrentMap<Object, ConcurrentMap<Object, Supplier<V>>> map = new ConcurrentHashMap<>();
// reverseMap記錄了所有代理類生成器是否可用, 這是為了實現緩存的過期機制
private final ConcurrentMap<Supplier<V>, Boolean> reverseMap = new ConcurrentHashMap<>();
// 生成二級緩存key的工廠, 這里傳入的是KeyFactory
private final BiFunction<K, P, ?> subKeyFactory;
// 生成二級緩存value的工廠, 這里傳入的是ProxyClassFactory
private final BiFunction<K, P, V> valueFactory;
/**
* Construct an instance of {@code WeakCache}
*
* @param subKeyFactory a function mapping a pair of
* {@code (key, parameter) -> sub-key}
* @param valueFactory a function mapping a pair of
* {@code (key, parameter) -> value}
* @throws NullPointerException if {@code subKeyFactory} or
* {@code valueFactory} is null.
*/
// 構造器,上面初始化proxyClassCache用到的
public WeakCache(BiFunction<K, P, ?> subKeyFactory,
BiFunction<K, P, V> valueFactory) {
this.subKeyFactory = Objects.requireNonNull(subKeyFactory);
this.valueFactory = Objects.requireNonNull(valueFactory);
}
/**
* Look-up the value through the cache. This always evaluates the
* {@code subKeyFactory} function and optionally evaluates
* {@code valueFactory} function if there is no entry in the cache for given
* pair of (key, subKey) or the entry has already been cleared.
*
* @param key possibly null key
* @param parameter parameter used together with key to create sub-key and
* value (should not be null)
* @return the cached value (never null)
* @throws NullPointerException if {@code parameter} passed in or
* {@code sub-key} calculated by
* {@code subKeyFactory} or {@code value}
* calculated by {@code valueFactory} is null.
*/
// 這個方法我們下面詳細講
public V get(K key, P parameter) {
...
}
...
}
上面的一個小插曲,現在繼續講 WeakCache.java 中的 get 方法
// K和P就是WeakCache定義中的泛型,key是類加載器,parameter是接口類數組
public V get(K key, P parameter) {
// 驗證接口類數組不為空
Objects.requireNonNull(parameter);
// 清除無效的緩存
expungeStaleEntries();
// 將ClassLoader包裝成CacheKey, 作為一級緩存的key
Object cacheKey = CacheKey.valueOf(key, refQueue);
// lazily install the 2nd level valuesMap for the particular cacheKey
// 獲取二級緩存
ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);
// 如果緩存中沒有,向緩存中放入數據
if (valuesMap == null) {
// CAS方式put,如果不存在則放入,存在則不放入。放入后會返回null,沒有放入會返回當前的value
ConcurrentMap<Object, Supplier<V>> oldValuesMap
= map.putIfAbsent(cacheKey,
valuesMap = new ConcurrentHashMap<>());
// 如果oldValuesMap有值, 說明放入失敗,也說明已經存在了,會把 valuesMap 刷新回以前存在的值
if (oldValuesMap != null) {
valuesMap = oldValuesMap;
}
}
// create subKey and retrieve the possible Supplier<V> stored by that
// subKey from valuesMap
// 根據代理類實現的接口數組來生成二級緩存key, 分為key0, key1, key2, keyx
Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
// 根據subKey獲取到二級緩存的值
Supplier<V> supplier = valuesMap.get(subKey);
Factory factory = null;
// 這個循環提供了輪詢機制, 如果條件為假就繼續重試直到條件為真為止
while (true) {
if (supplier != null) {
// supplier might be a Factory or a CacheValue<V> instance
// 在這里supplier可能是一個Factory也可能會是一個CacheValue
// 在這里不作判斷, 而是在Supplier實現類的get方法里面進行驗證
// 下面詳細講這個方法
V value = supplier.get();
if (value != null) {
return value;
}
}
// else no supplier in cache
// or a supplier that returned null (could be a cleared CacheValue
// or a Factory that wasn't successful in installing the CacheValue)
// lazily construct a Factory
if (factory == null) {
// 新建一個Factory實例作為subKey對應的值
factory = new Factory(key, parameter, subKey, valuesMap);
}
if (supplier == null) {
// 到這里表明subKey沒有對應的值, 就將factory作為subKey的值放入
supplier = valuesMap.putIfAbsent(subKey, factory);
if (supplier == null) {
// successfully installed Factory
// 到這里表明成功將factory放入緩存
supplier = factory;
}
// else retry with winning supplier
} else { // 否則, 可能期間有其他線程修改了值, 那么就不再繼續給subKey賦值, 而是取出來直接用
if (valuesMap.replace(subKey, supplier, factory)) {
// successfully replaced
// cleared CacheEntry / unsuccessful Factory
// with our Factory
// 成功將factory替換成新的值
supplier = factory;
} else {
// retry with current supplier
// 替換失敗, 繼續使用原先的值
supplier = valuesMap.get(subKey);
}
}
}
}
WeakCache的get方法並沒有用鎖進行同步,那它是怎樣實現線程安全的呢?因為它的所有會進行修改的成員變量都使用了ConcurrentMap,這個類是線程安全的。因此它將自身的線程安全委托給了ConcurrentMap, get方法盡可能的將同步代碼塊縮小,這樣可以有效提高WeakCache的性能。我們看到ClassLoader作為了一級緩存的key,這樣可以首先根據ClassLoader篩選一遍,因為不同ClassLoader加載的類是不同的。然后它用接口數組來生成二級緩存的key,這里它進行了一些優化,因為大部分類都是實現了一個或兩個接口,所以二級緩存key分為key0,key1,key2,keyX。key0到key2分別表示實現了0到2個接口,keyX表示實現了3個或以上的接口,事實上大部分都只會用到key1和key2。這些key的生成工廠是在Proxy類中,通過WeakCache的構造器將key工廠傳入。這里的二級緩存的值是一個Factory實例,最終代理類的值是通過Factory這個工廠來獲得的
再詳細講 supplier.get()
@Override
public synchronized V get() { // serialize access
// re-check
// 從二級緩存里面再獲取Supplier, 用來驗證是否是Factory本身
Supplier<V> supplier = valuesMap.get(subKey);
if (supplier != this) {
// something changed while we were waiting:
// might be that we were replaced by a CacheValue
// or were removed because of failure ->
// return null to signal WeakCache.get() to retry
// the loop
// 在這里驗證supplier是否是Factory實例本身, 如果不則返回null讓調用者繼續輪詢重試
// 期間supplier可能替換成了CacheValue, 或者由於生成代理類失敗被從二級緩存中移除了
return null;
}
// else still us (supplier == this)
// create new value
V value = null;
try {
// 委托valueFactory去生成代理類, 這里會通過傳入的ProxyClassFactory去生成代理類
// 后面詳細講 ProxyClassFactory 代理類工廠,代理對象就是在這里產生的
value = Objects.requireNonNull(valueFactory.apply(key, parameter));
} finally {
if (value == null) { // remove us on failure
// 如果生成代理類失敗, 就將這個二級緩存刪除
valuesMap.remove(subKey, this);
}
}
// the only path to reach here is with non-null value
// 只有value的值不為空才能到達這里
assert value != null;
// wrap value with CacheValue (WeakReference)
// 使用弱引用包裝生成的代理類
CacheValue<V> cacheValue = new CacheValue<>(value);
// put into reverseMap
// 將cacheValue成功放入二級緩存后, 再對它進行標記
reverseMap.put(cacheValue, Boolean.TRUE);
// try replacing us with CacheValue (this should always succeed)
// 用緩存包裝類替換this,必須成功,否則拋出異常
if (!valuesMap.replace(subKey, this, cacheValue)) {
throw new AssertionError("Should not reach here");
}
// successfully replaced us with new CacheValue -> return the value
// wrapped by it
return value;
}
最后一個核心方法 valueFactory.apply(key, parameter) 通過該方法就生成了代理類字節碼
Proxy.java->ProxyClassFactory->apply();
// 這個代理類工廠是在Proxy類初始化proxyClassCache靜態變量時傳入的
private static final class ProxyClassFactory
implements BiFunction<ClassLoader, Class<?>[], Class<?>>
{
// prefix for all proxy class names
// 所有代理類的前綴,我們在debug的時候看到的JDK代理對象都是這樣的
private static final String proxyClassNamePrefix = "$Proxy";
// next number to use for generation of unique proxy class names
// 用於生成代理類名字的計數器
private static final AtomicLong nextUniqueNumber = new AtomicLong();
@Override
public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
// 驗證接口
// 1. 驗證類加載器加載的對象接口是否是同一個
// 2. 驗證類對象是否是一個接口
// 3. 驗證此接口是否重復
for (Class<?> intf : interfaces) {
/*
* Verify that the class loader resolves the name of this
* interface to the same Class object.
*/
Class<?> interfaceClass = null;
try {
interfaceClass = Class.forName(intf.getName(), false, loader);
} catch (ClassNotFoundException e) {
}
if (interfaceClass != intf) {
throw new IllegalArgumentException(
intf + " is not visible from class loader");
}
/*
* Verify that the Class object actually represents an
* interface.
*/
if (!interfaceClass.isInterface()) {
throw new IllegalArgumentException(
interfaceClass.getName() + " is not an interface");
}
/*
* Verify that this interface is not a duplicate.
*/
if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
throw new IllegalArgumentException(
"repeated interface: " + interfaceClass.getName());
}
}
// 生成的代理類的包名
String proxyPkg = null; // package to define proxy class in
// 代理類訪問控制符
int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
/*
* Record the package of a non-public proxy interface so that the
* proxy class will be defined in the same package. Verify that
* all non-public proxy interfaces are in the same package.
*/
// 記錄非公共代理接口的包,以便在同一個包中定義代理類。驗證所有非公共代理接口都在同一個包中。
for (Class<?> intf : interfaces) {
int flags = intf.getModifiers();
if (!Modifier.isPublic(flags)) {
accessFlags = Modifier.FINAL;
String name = intf.getName();
int n = name.lastIndexOf('.');
String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
if (proxyPkg == null) {
proxyPkg = pkg;
} else if (!pkg.equals(proxyPkg)) {
throw new IllegalArgumentException(
"non-public interfaces from different packages");
}
}
}
if (proxyPkg == null) {
// if no non-public proxy interfaces, use com.sun.proxy package
proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
}
/*
* Choose a name for the proxy class to generate.
*/
long num = nextUniqueNumber.getAndIncrement();
// 代理類的全限定名稱:com.sun.proxy.$Proxy0
String proxyName = proxyPkg + proxyClassNamePrefix + num;
/*
* Generate the specified proxy class.
*/
// 核心代碼,生成代理類的字節碼
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces, accessFlags);
try {
// 把代理類加載到JVM中,至此代理類創建完成了
return defineClass0(loader, proxyName,
proxyClassFile, 0, proxyClassFile.length);
} catch (ClassFormatError e) {
/*
* A ClassFormatError here means that (barring bugs in the
* proxy class generation code) there was some other
* invalid aspect of the arguments supplied to the proxy
* class creation (such as virtual machine limitations
* exceeded).
*/
throw new IllegalArgumentException(e.toString());
}
}
}
我們再看看Factory這個內部工廠類,可以看到它的get方法是使用synchronized關鍵字進行了同步。進行get方法后首先會去驗證subKey對應的suppiler是否是工廠本身,如果不是就返回null,而WeakCache的get方法會繼續進行重試。如果確實是工廠本身,那么就會委托ProxyClassFactory生成代理類,ProxyClassFactory是在構造WeakCache的時候傳入的。所以這里解釋了為什么最后會調用到Proxy的ProxyClassFactory這個內部工廠來生成代理類。生成代理類后使用弱引用進行包裝並放入reverseMap中,最后會返回原裝的代理類
探究代理類長什么樣
上面把JDK動態代理的過程分析完了,但是我這探究的心里還是有一道過不去的坎,動態代理存在什么地方了?跟我們直接實現的類有什么區別呢?下面繼續研究解答這兩個問題
通過下面的main方法就可以輸出到磁盤代理對象
public class GenerateClient {
public static void main(String[] args) {
// 在main方法最前面增加該行代碼,這樣會輸出代理class文件
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");
UserService userService = new UserService();
UserInterface proxy = (UserInterface) new ProxyFactory(userService, null).getProxyObjectByTarget();
proxy.update();
}
}
通過上面的代碼就可以生成動態代理class文件了,在我們項目路徑下com/sun/proxy/$Proxy0.class,我的項目路徑是 D:/workspace-mine/spring_boot,那我都文件就在這個地址下 D:/workspace-mine/spring_boot/com/sun/proxy/$Proxy0.class
上面這種方式可以保存到磁盤上,但是在JVM中代理對象是保存在內存中的,我們看不到
代理對象的樣子
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package com.sun.proxy;
import com.example.spring_boot.modules.study.proxyobject.jdkproxy.UserInterface;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
public final class $Proxy0 extends Proxy implements UserInterface {
private static Method m1;
private static Method m4;
private static Method m2;
private static Method m0;
private static Method m3;
// 代理類的構造函數,其參數正是是InvocationHandler實例,
// Proxy.newInstance方法就是通過通過這個構造函數來創建代理實例的
public $Proxy0(InvocationHandler var1) throws {
super(var1);
}
public final boolean equals(Object var1) throws {
try {
return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final void save() throws {
try {
super.h.invoke(this, m4, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final String toString() throws {
try {
return (String)super.h.invoke(this, m2, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final int hashCode() throws {
try {
return (Integer)super.h.invoke(this, m0, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final void update() throws {
try {
super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m4 = Class.forName("com.example.spring_boot.modules.study.proxyobject.jdkproxy.UserInterface").getMethod("save");
m2 = Class.forName("java.lang.Object").getMethod("toString");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
m3 = Class.forName("com.example.spring_boot.modules.study.proxyobject.jdkproxy.UserInterface").getMethod("update");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
可以看到上面重寫了toString、equals、hashCode三個方法,生成了5個方法變量,分別指向各自的方法,其中m4和m3是接口中的save和update方法
上面重要的一個是構造函數$Proxy0,這個構造函數在代理對象還沒有生成前是不起做用的,直到代理對象生成了,這個構造器里面的參數就是我們在Proxy.newProxyInstance中傳入的new InvocationHandler(){...}這樣就開始執行我們構造器的方法了
如果想要在代理對象中執行代理方法可以直接這樣寫(main方法放在代理對象后面,需要把代理class轉成java)
public static void main(String[] args) {
UserService userService = new UserService();
$Proxy0 proxyObject = new $Proxy0(new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("在代理對象中執行main方法開始...");
method.invoke(userService, args);
System.out.println("在代理對象中執行main方法結束...");
return null;
}
});
proxyObject.save();
}
Cglib動態代理
敬請期待...
