深入理解JDK動(dòng)態(tài)代理
代理模式的目的是在不修改原有類方法設(shè)計(jì)的基礎(chǔ)上,對(duì)方法行為進(jìn)行增強(qiáng)。
為了好理解,舉個(gè)實(shí)際場(chǎng)景,我們業(yè)務(wù)場(chǎng)景中經(jīng)常有限流的需求,常規(guī)操作是在需要限流的接口代碼前加入調(diào)用次數(shù)判斷的代碼,但是這樣每個(gè)需要限流的方法都需要加,工作量大不說(shuō),一方面不好維護(hù),不能很清晰的知道每個(gè)接口限流值,另一方面,限流代碼和業(yè)務(wù)代碼堆疊在一起,也影響代碼閱讀。解法是做一套統(tǒng)一限流,一般好點(diǎn)的會(huì)有專門的接口限流平臺(tái),配置對(duì)應(yīng)的接口名,設(shè)置限流值,直接就可以限流,實(shí)現(xiàn)方式就可以用動(dòng)態(tài)代理。不修改原接口的實(shí)現(xiàn),對(duì)接口進(jìn)行增強(qiáng)。
動(dòng)態(tài)代理的優(yōu)勢(shì)是實(shí)現(xiàn)無(wú)侵入式的代碼擴(kuò)展,做方法的增強(qiáng);讓你可以在不用修改源碼的情況下,增強(qiáng)一些方法;在方法的前后你可以做你任何想做的事情(甚至不去執(zhí)行這個(gè)方法就可以)。
靜態(tài)代理
既然有動(dòng)態(tài),那一定有靜態(tài),說(shuō)下區(qū)別吧,
靜態(tài):最大的區(qū)別是靜態(tài)是編譯期就決定了,在程序運(yùn)行之前,代理類的.class文件已經(jīng)存在了。被代理類是什么,代理類實(shí)現(xiàn)方式。
舉個(gè)栗子:
我現(xiàn)在有個(gè)接口,是把Json字符串解析成Object 對(duì)象,接口如下:
- public interface IProvider {
 - Object getData(String json);
 - }
 
接口的實(shí)現(xiàn)類如下:
- public class SimpleProvider implements IProvider {
 - @Override
 - public Object getData(String json) {
 - //解析json 拿到數(shù)據(jù)
 - return parseJson(json);
 - }
 
那現(xiàn)在有個(gè)需求,需要對(duì) getData 方法做限流,指定用靜態(tài)代理的方式。
需要很簡(jiǎn)單,我就直接貼了:
- public class ProviderProxy implements IProvider{
 - //持有一個(gè)被代理對(duì)象的引用(在這里是SimpleProvider)
 - IProvider iProvider;
 - public StaticProviderProxy(IProvider iProvider){
 - this.iProvider = iProvider;
 - }
 - @Override
 - public Object getData(String json) {
 - //做限流檢查
 - if(callSpeed > flowLimt) {
 - //流量超限
 - throw FlowLimitException();
 - }
 - Object object = iProvider.getData(json);
 - return object;
 - }
 - }
 - //main
 - public static void main(String[] args) {
 - IProvider provider = new ProviderProxy(new SimpleProvider());
 - provider.getData("{\"data\":{}}");
 - }
 
這就是靜態(tài)代理,代理類(ProviderProxy)實(shí)現(xiàn)和需要做方法增強(qiáng)的被代理類(SimpleProvider)實(shí)現(xiàn)同一個(gè)接口(IProvider),方法具體實(shí)現(xiàn)上做增強(qiáng),這里是限流檢查。
動(dòng)態(tài)代理
Java 動(dòng)態(tài)代理
- 動(dòng)態(tài)代理類:在程序運(yùn)行時(shí),通過(guò)反射機(jī)制動(dòng)態(tài)生成。
 - 動(dòng)態(tài)代理類通常代理接口下的所有類。靜態(tài)一般指定某個(gè)類代理。
 - 動(dòng)態(tài)代理事先不知道要代理的是什么,只有在運(yùn)行的時(shí)候才能確定。靜態(tài)是編譯期確定的。
 
還是以IProvider 接口為例,同樣是要對(duì) SimpleProvider 做增強(qiáng),如下:
- public class ProviderHandler implements InvocationHandler {
 - Object target;
 - public Object bind(Object target){
 - this.target = target;
 - //這里生成了代理對(duì)象
 - return Proxy.newProxyInstance(target.getClass().getClassLoader(),
 - target.getClass().getInterfaces(), this);
 - }
 - @Override
 - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
 - //限流
 - flowLimit(args);
 - Object obj = method.invoke(target, args);
 - //打印日志
 - logger.info("print log...");
 - return obj;
 - }
 - }
 - //main
 - public static void main(String[] args) {
 - ProviderHandler providerHandler = new ProviderHandler();
 - IProvider iProvider = (IProvider) providerHandler.bind(new SimpleProvider());
 - iProvider.getData("weibo.data");
 - }
 
這里有三個(gè)對(duì)象:
SimpleProvider 對(duì)象 , 我們稱之為被代理對(duì)象
ProviderHandler 對(duì)象,我們稱之為執(zhí)行者對(duì)象
Proxy對(duì)象 (通過(guò)在ProviderHandler bind方法中使用Proxy.newProxyInstance生成的對(duì)象) 我們稱之為代理對(duì)象
這三個(gè)對(duì)象是什么關(guān)系呢?
Proxy是真正的代理類,SimpleProvider是被代理類,ProviderHandler是執(zhí)行方法增強(qiáng)的執(zhí)行者。
我們是為了增強(qiáng)SimpleProvider (被代理對(duì)象)的getData方法,就Proxy對(duì)象來(lái)代理被代理對(duì)象的執(zhí)行,Proxy不親自來(lái)做這件事,而是交給執(zhí)行者對(duì)象ProviderHandler 來(lái)實(shí)現(xiàn)增加的目錄,執(zhí)行調(diào)用前的限流校驗(yàn)。
實(shí)際怎么實(shí)現(xiàn)的呢?
newProxyInstance源碼
- public static Object newProxyInstance(ClassLoader loader,
 - Class<?>[] interfaces,
 - InvocationHandler h)
 - throws IllegalArgumentException
 - {
 - //對(duì) Invocationhandler做判空處理
 - Objects.requireNonNull(h);
 - //復(fù)制[IProvider接口]
 - final Class<?>[] intfs = interfaces.clone();
 - //根據(jù)IProvider的類加載器IProvider接口生成了Proxy類,關(guān)鍵:根據(jù)類加載器和接口對(duì)象在JVM緩存中生成一個(gè)類對(duì)象
 - Class<?> cl = getProxyClass0(loader, intfs);
 - //獲取構(gòu)造器
 - final Constructor<?> cons = cl.getConstructor(constructorParams);
 - //保存InvocationHandler的引用
 - final InvocationHandler ih = h;
 - //通過(guò)構(gòu)造器實(shí)例化Proxy代理對(duì)象
 - return cons.newInstance(new Object[]{h});
 - }
 
代碼注釋寫的很清晰。
可能這個(gè)地方大家都會(huì)疑惑,生成的Proxy對(duì)象是怎樣調(diào)用執(zhí)行者的invoke函數(shù)的。
這個(gè)地方通過(guò)這段代碼將Proxy0的class字節(jié)碼輸出到文件。
- byte[] classFile = ProxyGenerator.generateProxyClass("$Proxy0", WeiboProvider.class.getInterfaces());
 - String path = "C:**/IdeaProjects/study/out/production/study/SimpleProxy.class";
 - try(FileOutputStream fos = new FileOutputStream(path)) {
 - fos.write(classFile);
 - fos.flush();
 - System.out.println("代理類class文件寫入成功");
 - } catch (Exception e) {
 - System.out.println("寫文件錯(cuò)誤");
 - }
 
反編譯Proxy0如下:
- //Proxy0 是動(dòng)態(tài)生成的類,繼承自Proxy,實(shí)現(xiàn)了IProvider接口
 - public final class $Proxy0 extends Proxy implements IProvider {
 - private static Method m1;
 - private static Method m2;
 - private static Method m3;
 - private static Method m0;
 - 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})).booleanValue();
 - } catch (RuntimeException | Error var3) {
 - throw var3;
 - } catch (Throwable var4) {
 - throw new UndeclaredThrowableException(var4);
 - }
 - }
 - 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 String getData(String var1) throws {
 - try {
 - //m3就是IProvider 接口的getData方法
 - //super.h 是父類java.lang.reflect.Proxy的屬性 InvocationHandler
 - return (String)super.h.invoke(this, m3, new Object[]{var1});
 - } catch (RuntimeException | Error var3) {
 - throw var3;
 - } catch (Throwable var4) {
 - throw new UndeclaredThrowableException(var4);
 - }
 - }
 - public final int hashCode() throws {
 - try {
 - return ((Integer)super.h.invoke(this, m0, (Object[])null)).intValue();
 - } catch (RuntimeException | Error var2) {
 - throw var2;
 - } catch (Throwable var3) {
 - throw new UndeclaredThrowableException(var3);
 - }
 - }
 - static {
 - try {
 - 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就是IProvider 接口的getData方法
 - m3 = Class.forName("aop.IProvider").getMethod("getData", new Class[]{Class.forName("java.lang.String")});
 - m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
 - } catch (NoSuchMethodException var2) {
 - throw new NoSuchMethodError(var2.getMessage());
 - } catch (ClassNotFoundException var3) {
 - throw new NoClassDefFoundError(var3.getMessage());
 - }
 - }
 - }
 
重點(diǎn)在 return (String)super.h.invoke(this, m3, new Object[]{var1});代碼。
$Proxy0繼承Proxy類,實(shí)現(xiàn)了IProvider接口,所以也有g(shù)etData()函數(shù),而getData函數(shù)調(diào)用的是執(zhí)行者InvocationHandler的invoke方法,m3是通過(guò)反射拿到的Method對(duì)象,所以看getData調(diào)用invoke傳遞的。三個(gè)參數(shù),第一個(gè)是Proxy對(duì)象,第二個(gè)是getData方法對(duì)象,第三個(gè)是參數(shù)。
總結(jié)一下:
- 動(dòng)態(tài)代理的本質(zhì)就是,生成一個(gè)繼承自Proxy,實(shí)現(xiàn)被代理接口(IProvider)的類 - Proxy0。
 - Proxy0 持有InvocationHandler實(shí)例,InvocationHandler 持有SimpleProvider實(shí)例。Proxy0調(diào)用接口 getData方法時(shí),先傳遞給InvocationHandler,InvocationHandler再傳遞給SimpleProvider實(shí)例。
 
動(dòng)態(tài)代理實(shí)際上就是幫我們?cè)贘VM內(nèi)存中直接重新生成了代理類class和對(duì)應(yīng)類對(duì)象,然后通過(guò)執(zhí)行者InvocationHandler調(diào)用被代理對(duì)象SimpleProvider。
Spring AOP中的代理
Spring代理其實(shí)是對(duì)JDK動(dòng)態(tài)代理和CGLIB代理進(jìn)行了封裝,并且引入了AOP的概念,同時(shí)引入了AspectJ中的一些注解:@pointCut @After 等。
- public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
 - if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
 - Class<?> targetClass = config.getTargetClass();
 - if (targetClass == null) {
 - throw new AopConfigException("TargetSource cannot determine target class: " +
 - "Either an interface or a target is required for proxy creation.");
 - }
 - // 如果是接口,使用jdk代理
 - if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
 - return new JdkDynamicAopProxy(config);
 - }
 - //否則使用cglib
 - return new ObjenesisCglibAopProxy(config);
 - }
 - else {
 - return new JdkDynamicAopProxy(config);
 - }
 - }
 
















 
 
 











 
 
 
 