動態代理與AOP原理
阿新 • • 發佈:2021-09-15
靜態代理
要知道什麼是動態代理,首先要知道什麼是靜態代理?
package DynamicProxy; /** * 頂層介面 */ interface ClothFactory{ void produce(String product); } /** * 被代理類:相當於品牌、企業 * 因為在建立代理類物件的時候需要建立被代理類的物件,所以兩個類都需要實現ClothFactory介面 */ class NikeClothFactory implements ClothFactory{ @Override public void produce(String product) { System.out.println("Nike"+product); } } /** * 代理類:相當於生產衣服的工廠代理商販 */ class ProxyClothFactory implements ClothFactory{ // 用被代理類物件進行例項化 private ClothFactory factory; // 構造器:表示代理的是誰 public ProxyClothFactory(ClothFactory factory) { this.factory = factory; } // 代理類具體要做的事情:看似是被代理類做的事情,實際上是代理類做的事情 @Override public void produce(String product) { System.out.println("代理工廠做一些準備工作..."); factory.produce("生產一批"+product); System.out.println("代理工廠做一些後續的收尾工作.."); } } /** * 測試類: */ public class staticProxy { public static void main(String[] args) { // 建立被代理類的物件 NikeClothFactory ncf = new NikeClothFactory(); // 建立代理類的物件 ProxyClothFactory pcf = new ProxyClothFactory(ncf); pcf.produce("Air Force1"); } }
動態代理
動態代理demo
package DynamicProxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; /** * 頂層介面: * 動態代理測試: * 不論是動態代理還是靜態代理都需要有介面和被代理類 * 區別就是:代理類物件是在什麼時候建立的,建立了幾個。 */ interface Human{ String getBelif(); void eat(String food); } /** * 被代理類:實現頂層介面抽象方法 */ class SuperMan implements Human{ @Override public String getBelif() { return "I believe I can fly~"; } @Override public void eat(String food) { System.out.println("我喜歡吃"+food); } } /** * 如何建立動態代理類? * 要想實現動態代理需要解決下面2個問題: * 問題1. 如何根據已經載入到記憶體中的被代理類,動態的建立一個代理類及其物件 * 問題2. 當通過代理類的物件呼叫方法時,如何動態的去呼叫被代理類中的同名方法 */ class ProxyFactory{ // 問題1:呼叫此方法,返回一個代理類的物件,這樣就動態的建立了一個代理類的物件。其中obj表示被代理類的物件,表示代理誰 public static Object getProxyInstance(Object obj){ /** * 引數1:獲取被代理類的載入器 * 引數2:獲取被代理類實現了哪些介面 * 引數3:獲取代理類呼叫了哪些被代理類的方法,需要自己寫介面實現類,去實現InvocationHandler介面,並且重寫invoke方法的時候,如果代理類物件呼叫某方法a時,會自動的呼叫invoke方法 */ MyInvocationhandler handler = new MyInvocationhandler(); // 呼叫bind方法,指明具體呼叫了哪個被代理類.因為obj就是被代理類的物件 handler.bind(obj); return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),handler); } } /** * 如何建立動態代理類? * */ class MyInvocationhandler implements InvocationHandler{ // 宣告被代理類的物件,但是不能確定是哪個物件,所以寫Object型別 private Object obj; // 對被代理類的物件進行賦值 public void bind(Object obj){ this.obj = obj; } /** * invoke裡面寫被代理類的方法的邏輯,但是被代理物件還沒有需要在上面提前建立 * 引數1:就是上面ProxyFactory中方法返回的物件 * 引數2:代理類物件呼叫的方法,此方法也就作為了被代理類物件要呼叫的方法 * 引數3:呼叫方法傳遞的實參 */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 傳入被代理類物件和引數,呼叫的是被代理類的哪個方法 Object invoke = method.invoke(obj, args); // 返回的invoke實際上就是被代理類物件的返回值 return invoke; } } /** * 測試: * 1.建立被代理類物件 * 2.動態的建立代理類的物件,傳入被代理類物件 * 3.有了代理類物件就可以通過代理類物件invoke方法呼叫被代理類物件的方法和屬性 */ public class DynamicProxy { public static void main(String[] args) { // 1.建立被代理類物件 SuperMan man = new SuperMan(); // 2.動態的建立代理類的物件:需要用頂層介面Human接收,因為如果不強轉為Human就不能呼叫被代理類重寫的抽象方法,並且她們都實現了Human介面 // 用Object接收是不對的 //Object proxyInstance = ProxyFactory.getProxyInstance(man); Human proxyInstance1 = (Human)ProxyFactory.getProxyInstance(man); String belief = proxyInstance1.getBelif(); System.out.println(belief); proxyInstance1.eat("重慶小火鍋"); System.out.println("****************把靜態代理類的例子也改成動態代理實現:****************"); //1.建立被代理類物件 NikeClothFactory nike = new NikeClothFactory(); // 2.動態的建立代理類的物件 ClothFactory proxyInstance2 = (ClothFactory)ProxyFactory.getProxyInstance(nike); proxyInstance2.produce("Nike daybreak"); } }