一、動態代理模式簡單理解:
動態代理生成一個對象的代理,這個代理對象擁有和原對象的所有屬性和行爲,而且還多出另外功能。舉個例子:現在有一個對象A1,A1有個方法test(),用動態代理生成對等代理對象A2,A2可以像A1調用test()方法,但是A2會在調用過程插入一些額外的操作。
二、動態代理(JDK)
- 代理對象接口和實現類,下面代碼中的TestService和TestServiceImpl
- 代理類,下面代碼中的ProxyUtils,需要實現InvocationHandle,實現invoke()方法
- 客戶端使用ProxyUtils生成TestService代理對象,調用方法,代碼中的test()方法
三、代碼實現(推薦在本地跑下,加深理解)
代碼實現過程中加入了對SpringAOP的解析,加入了Interceptor攔截器,在代理對象生成類中invoke()方法中實現SpringAOP中的@Before、@After、@AfterReturning、@AfterThrowing註解
- 代理對象接口和實現類TestService和TestServiceImpl
public interface TestService {
public void test();
}
public class TestServiceImpl implements TestService {
@Override
public void test() {
System.out.println("測試開始#############");
}
}
- 代理類ProxyUtils,需要實現InvocationHandle,實現invoke()方法
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* 生成代理對象工具類
* @param <T>
*/
public class ProxyUtils<T> implements InvocationHandler {
private TestService testService;
private Interceptor interceptor;
/**
* 生成代理對象
*
* @param testService
* @param interceptor
* @return
*/
public Object getProxy (TestService testService, Interceptor interceptor) {
this.testService = testService;
this.interceptor = interceptor;
ClassLoader testServiceClassLoader = testService.getClass().getClassLoader();
Class[] testServiceInterfaces = testService.getClass().getInterfaces();
return Proxy.newProxyInstance(testServiceClassLoader, testServiceInterfaces, this);
}
/**
* 執行真實方法步驟:
* 1、先執行before方法
* 2、通過method.invoker執行test()方法
* 3、如果執行test()成功,執行afterReturning方法;否則執行afterThrowing方法
* 4、最終執行after方法
*
* @param proxy
* @param method
* @param args
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//標記是否出現異常
boolean error = false;
interceptor.before(); //實現SpringAOP中的Before()方法
try{
method.invoke(args);
}
catch (Exception e) {
error = true;
e.printStackTrace();
}
finally {
interceptor.after(); //實現SpringAOP中的After()方法
}
if (error){
interceptor.afterThrowing(); //實現SpringAOP中的AfterThrowing()方法
}
else {
interceptor.afterReturning(); //實現SpringAOP中的AfterReturning()方法
}
return null;
}
}
- 客戶端使用ProxyUtils生成TestService代理對象,調用方法,代碼中的test()方法
/**
* 動態代理測試客戶端
*/
public class Client {
public static void main(String[] args) {
TestService testService = new TestServiceImpl();
Interceptor interceptor = new TestServiceInterceptor();
ProxyUtils proxyUtils = new ProxyUtils();
TestService proxy = (TestService) proxyUtils.getProxy(testService, interceptor);
System.out.println("proxy = " + proxy.getClass().getName());
proxy.test();
}
}
四、源碼解析
代理對象生成類中兩大關鍵點:
Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h);
生成代理對象的過程如下:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h);
{
Objects.requireNonNull(h);
final Class<?> caller = System.getSecurityManager() == null
? null
: Reflection.getCallerClass();
/*
* Look up or generate the designated proxy class and its constructor.
*/
Constructor<?> cons = getProxyConstructor(caller, loader, interfaces);
return newProxyInstance(caller, cons, h);
}
說明:上述代碼其實是使用反射機制ClassLoader獲取對象的Constructor,然後使用Constructor生成類的對象,對等下面的代碼:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h);
{
Constructor constructor = testServiceClassLoader.getClass().getConstructor(param);
return constructor.newInstance();
}
返回的代理對象proxy實現了newProxyInstance方法中的參數interfaces接口,並且proxy封裝了其他行爲,感興趣的同學可以看看$Proxy0類的實現,當我們執行proxy.test()方法時,首先會經過 $Proxy0調用InvocationHandle中的invoke()方法。