摘要:動態代理的產生就是這樣而來的。在的方案中我們只需要這樣做可以實現動態代理了。委托類實際執行類利用提供的實現動態代理代理環繞執行實際的方法利用的實現代理動態代理,有幾個關鍵點,一個就是接口,這個方法中的方法是執行代理時會執行的方法。
什么是代理?
代理是一種設計模式,簡單的說就是為某個對象提供代理,以控制這個對象的訪問,在不修改原方法的情況下做方法增強,簡單的可以分為兩種:
靜態代理
動態代理
靜態代理一般情況下的代理就是有一個接口,接口中定義了一些方法需要被實現,實現了那些方法的類被稱為實現類,但是當我們需要在調用該方法前做一些額外的操作,又不想影響原來的代碼,這時候就可以引入一個代理類,讓代理類也實現該接口,然后將接口的那個實現類作為成員變量引入代理類中,額外操作時由代理類操作,具體到該方法時則由實現類去操作,下面舉個例子;
public interface Calculator {
//需要代理的接口 public int add(int a,int b); //接口實現類,執行真正的a+b操作 public static class CalculatorImpl implements Calculator{ @Override public int add(int a, int b) { System.out.println("doing "); return a+b; } } //靜態代理類的實現.代碼已經實現好了. public static class CalculatorProxy implements Calculator{ private Calculator calculator; public CalculatorProxy(Calculator calculator) { this.calculator=calculator; } @Override public int add(int a, int b) { //執行一些操作 System.out.println("begin "); int result = calculator.add(a, b); System.out.println("end "); return result; } }
}
Calculator是一個計算器的接口類,定義了一個加法的接口方法,由CalculatorImpl類實現真正的加法操作.現在如果我們想對這個方法做一層靜態的代理,這兒實現了一個簡單的代理類實現了計算接口Calculator,構造函數傳入的參數是真正的實現類,但是在調用這個代理類的add方法的時候我們在CalculatorImpl的實現方法執行的前后分別做了一些操作。這樣的代理方式就叫做靜態代理(這個是別人的例子,只是為了更加形象的展示靜態代理,拿代碼說話)。
很明顯靜態代理的缺點,由于我們需要事先實現代理類,那么每個方法我都都需要去實現。如果我們要實現很多的代理類,那么工作量就太大了。動態代理的產生就是這樣而來的。
動態代理使用動態代理可以讓代理類在程序運行的時候生成代理類,我們只需要為一類代理寫一個具體的實現類就行了,所以實現動態代理要比靜態代理簡單許多,省了不少重復的工作。在JDK的方案中我們只需要這樣做可以實現動態代理了。
public class ProxyFactory implements InvocationHandler {
private Class> target; private Object real; //委托類class public ProxyFactory(Class> target){ this.target=target; } //實際執行類bind public Object bind(Object real){ this.real=real; //利用JDK提供的Proxy實現動態代理 return Proxy.newProxyInstance(target.getClassLoader(),new Class[]{target},this); } @Override public Object invoke(Object o, Method method, Object[] args) throws Throwable { //代理環繞 System.out.println("begin"); //執行實際的方法 Object invoke = method.invoke(real, args); System.out.println("end"); return invoke; } public static void main(String[] args) { Calculator proxy =(Calculator) new ProxyFactory(Calculator.class).bind(new Calculator.CalculatorImpl()); proxy.add(1,2); }
}
利用JDK的proxy實現代理動態代理,有幾個關鍵點,一個就是InvocationHandler接口,這個方法中的invoke方法是執行代理時會執行的方法。所以我們所有代理需要執行的邏輯都會寫在這里面,invo參數里面的method可以使用java 反射調用真實的實現類的方法,我們在這個方法周圍做一些代理邏輯工作就可以了。上面的代碼會把Calculator接口的所有方法全部在程序運行時代理。不用我們一個個的去寫靜態代理的方法。
public final class Calcultor$ProxyCode extends Proxy implements Calculator {
private static Method m1; private static Method m4; private static Method m0; private static Method m3; private static Method m2; public Calcultor$ProxyCode(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 int reduce(int var1, int var2) throws { try { return ((Integer)super.h.invoke(this, m4, new Object[]{Integer.valueOf(var1), Integer.valueOf(var2)})).intValue(); } catch (RuntimeException | Error var4) { throw var4; } catch (Throwable var5) { throw new UndeclaredThrowableException(var5); } } 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); } } public final int add(int var1, int var2) throws { try { return ((Integer)super.h.invoke(this, m3, new Object[]{Integer.valueOf(var1), Integer.valueOf(var2)})).intValue(); } catch (RuntimeException | Error var4) { throw var4; } catch (Throwable var5) { throw new UndeclaredThrowableException(var5); } } 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); } } static { try { //static靜態塊加載每個方法的Method對象 m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[]{Class.forName("java.lang.Object")}); m4 = Class.forName("jdkproxy.Calculator").getMethod("reduce", new Class[]{Integer.TYPE, Integer.TYPE}); m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]); m3 = Class.forName("jdkproxy.Calculator").getMethod("add", new Class[]{Integer.TYPE, Integer.TYPE}); m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]); } catch (NoSuchMethodException var2) { throw new NoSuchMethodError(var2.getMessage()); } catch (ClassNotFoundException var3) { throw new NoClassDefFoundError(var3.getMessage()); } }
}
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/67722.html
摘要:這種語法,在中被稱為動態代理。在動態代理機制中,這個角色只能是接口。動態代理就是實現的技術之一。 所謂動態代理,指的是語言提供的一種語法,能夠將對對象中不同方法的調用重定向到一個統一的處理函數中來。python重寫__getattr__函數能夠做到這一點,就連世界上最好的語言也提供稱為魔術方法的__call。這種語法除了能更好的實現動態代理外,還是RPC框架實現原理的一部分。 動態代理...
摘要:自定義注解不生效原因解析及解決方法背景項目中,自己基于實現了一套緩存注解。但是最近出現一種情況緩存竟然沒有生效,大量請求被擊穿到層,導致壓力過大。至此,問題得到解決。 自定義注解不生效原因解析及解決方法 背景: 項目中,自己基于spring AOP實現了一套java緩存注解。但是最近出現一種情況:緩存竟然沒有生效,大量請求被擊穿到db層,導致db壓力過大。現在我們看一下具體代碼情形(代...
摘要:由于的限制,無法替換被代理類已經被載入的字節碼,只能生成并載入一個新的子類作為代理類,被代理類的字節碼依然存在于中。區別于前兩者,是一種靜態代理的實現,即在編譯時或者載入類時直接修改被代理類文件的字節碼,而非運行時實時生成代理。 現象描述 上周同事發現其基于mySql實現的分布式鎖的線上代碼存在問題,代碼簡化如下: @Controller class XService { @A...
時間:2017年09月03日星期日說明:本文部分內容均來自慕課網。@慕課網:http://www.imooc.com 教學源碼:https://github.com/zccodere/s...學習源碼:https://github.com/zccodere/s... 第一章:課程介紹 1-1 面向切面 課程章節 概覽 AOP使用 AOP原理 AOP開源運用 課程實戰 課程總結 面向切面編程是一種...
摘要:動態代理又被稱為代理或接口代理。靜態代理在編譯時產生字節碼文件,可以直接使用,效率高。代理無需實現接口,通過生成類字節碼實現代理,比反射稍快,不存在性能問題,但會繼承目標對象,需要重寫方法,所以目標對象不能為類。 一、代理模式介紹 代理模式是一種設計模式,提供了對目標對象額外的訪問方式,即通過代理對象訪問目標對象,這樣可以在不修改原目標對象的前提下,提供額外的功能操作,擴展目標對象的功...
閱讀 1249·2023-04-26 02:38
閱讀 928·2023-04-25 20:13
閱讀 3589·2021-11-19 11:31
閱讀 2396·2019-08-30 15:55
閱讀 2717·2019-08-30 14:11
閱讀 3157·2019-08-30 13:45
閱讀 1371·2019-08-29 18:41
閱讀 1147·2019-08-29 16:18