Java学习之动态代理
Java動態代理
為什么使用動態代理
當需要對某個類的某個方法進行修飾(增強)的時候,可以使用繼承、裝飾者模式和動態代理。
三種方式局限性:
使用動態代理可以更加靈活地提高代碼的復用程度。
舉個栗子:
對于計算機教師這個類,有個teach()方法,時過境遷,舊的教學模式可能已經不適合高速發展的計算機行業了,因此在使用這個teach()方法可能需要前面或者后面要增加一點東西。但是對于老舊的項目,我們很難去理解前人的寫法和思維方式,因此不能輕易修改他們的代碼,所以我們可以使用代理去實現對teach()方法的增強(我這里分為前置增強和后置增強)。
如何使用動態代理
Object Proxy.newInstance(ClassLoader loader, Class[] interfaces, InvocationHandler ih)
InvocationHandler接口
該接口需要實現invoke()方法。
Object invoke(Object proxy, Method method, Object[] args)
在使用代理對象使用某個方法的時候,會調用生成代理對象時候傳入的InvocationHandler的invoke()方法,因此可以在這個invoke()里面寫需要增強的內容。
Demo
先給出兩個接口和一個實現類
public interface Subject {public int outPut(int num); } public interface BSubject {public int outPut2(int num); } public class realSubject implements Subject, BSubject {@Overridepublic int outPut(int num) {System.out.println("outPut " + String.valueOf(num) + " people");return num;}@Overridepublic int outPut2(int num) {System.out.println("outPut2 " + String.valueOf(num) + " people");return num;} }使用動態代理
前置增強接口:
public interface BeforeAdvance { // 前置增強接口public void before(); }后置增強接口:
public interface AfterAdvance { // 后置增強接口public void after(); }創建代理工廠,可以更加方便調用:
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy;public class ProxyFactory {private Object targetObject; // 目標代理對象private BeforeAdvance beforeAdvance; // 前置增強private AfterAdvance afterAdvance; // 后置增強public Object createFactory() {ClassLoader loader = this.getClass().getClassLoader(); // 加載.class到內存Class[] interfaces = targetObject.getClass().getInterfaces(); // 得到realSubject所有接口(Waiter), 給代理對象提供了一組接口,這個代理對象就會實現這組接口,InvocationHandler ih = new InvocationHandler() {@Override// proxy 是代理對象,是在jvm運行時動態生成的一個對象,它并不是我們的InvocationHandler類型,也不是我們定義的那組接口的類型,而是在運行是動態生成的一個對象// Method 是目標對象需要增強的方法// args是實參public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {if(beforeAdvance != null) { // 調用前置增強方法beforeAdvance.before();}Object result = method.invoke(targetObject, args); // 通過反射調用目標代理對象的目標方法, result是目標方法的返回值if(afterAdvance != null) { // 調用后置增強方法afterAdvance.after();}return result;}};return Proxy.newProxyInstance(loader, interfaces, ih); // 得到一個代理對象}public AfterAdvance getAfterAdvance() {return afterAdvance;}public void setAfterAdvance(AfterAdvance afterAdvance) {this.afterAdvance = afterAdvance;}public BeforeAdvance getBeforeAdvance() {return beforeAdvance;}public void setBeforeAdvance(BeforeAdvance beforeAdvance) {this.beforeAdvance = beforeAdvance;}public Object getTargetObject() {return targetObject;}public void setTargetObject(Object targetObject) {this.targetObject = targetObject;} }示例:
import org.junit.Test;public class Demo {@Testpublic void fun() {ProxyFactory proxyfactory = new ProxyFactory();// 代理的目標對象proxyfactory.setTargetObject(new realSubject());// 前置增強接口實現proxyfactory.setBeforeAdvance(new BeforeAdvance() {@Overridepublic void before() {System.out.println("hello");}});// 后置增強接口實現proxyfactory.setAfterAdvance(new AfterAdvance() {@Overridepublic void after() {System.out.println("byebye");}});// 生成對Subject接口的實現類對象Subject subject = (Subject) proxyfactory.createFactory(); // 通過newInstance()得到一個代理對象,這個代理對象實現了Subject接口,因此可以強轉為Subject接口類。BSubject subject2 = (BSubject) proxyfactory.createFactory();Object result = subject.outPut(100); // 對應InvocationHandler的invoke方法:subject為proxy, outPut為method, 參數為argsSystem.out.println(result);System.out.println("-----");Object result2 = subject2.outPut2(50);System.out.println(result2);} }輸出: hello outPut 100 people byebye 100 ----- hello outPut2 50 people byebye 50在這里面,只要使用反射,method.invoke()就可以調用代理的目標對象的該方法,然后實現前置增強BeforeAdvance接口和后置增強AfterAdvance接口,就可以實現對方法內容的增強了。
其中不同接口的不同實現方法都可以重用BeforeAdvance和AfterAdvance。
對于不同的增強對象也可以使用,只要targetObject改一下就可以了。
附上一篇講的不錯的文章
轉載于:https://www.cnblogs.com/fightfordream/p/7965479.html
總結
以上是生活随笔為你收集整理的Java学习之动态代理的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: SSM整合(2): spring 与 m
- 下一篇: 2017-2018-1 20155330