Java學習之動態代理

來源:互聯網
上載者:User

標籤:his   imp   內容   cat   unit   new   handler   cto   down   

Java動態代理為什麼使用動態代理

當需要對某個類的某個方法進行修飾(增強)的時候,可以使用繼承、裝飾者模式和動態代理。

三種方式局限性:

  1. 繼承:增強對象不能改變,增強內容不能改變。
  2. 裝飾者模式:增強對象不能改變,增強內容能改變。
  3. 動態代理:增強對象可以改變,增強內容可以改變。

使用動態代理可以更加靈活地提高代碼的複用程度。

舉個栗子:
對於電腦教師這個類,有個teach()方法,時過境遷,舊的教學模式可能已經不適合高速發展的電腦行業了,因此在使用這個teach()方法可能需要前面或者後面要增加一點東西。但是對於老舊的項目,我們很難去理解前人的寫法和思維方式,因此不能輕易修改他們的代碼,所以我們可以使用代理去實現對teach()方法的增強(我這裡分為前置增強和後置增強)。

如何使用動態代理Object Proxy.newInstance(ClassLoader loader, Class[] interfaces, InvocationHandler ih)
  1. loader:類載入器,將類載入到記憶體當中。
  2. interfaces:代理對象要實現的介面。
  3. ih:InvocationHandler,其中實現invoke()方法,來實現對目標對象的增強。
  4. 傳回值:jvm運行時動態產生的一個對象,它並不是我們的InvocationHandler類型,也不是我們定義的那組介面的類型,而是在運行是動態產生的一個對象
InvocationHandler介面

該介面需要實現invoke()方法。

Object invoke(Object proxy, Method method, Object[] args)
  1. proxy:代理對象。
  2. method:代理對象使用的目標方法。
  3. args:目標方法的參數。
  4. 傳回值:method方法的傳回值。

在使用代理對象使用某個方法的時候,會調用組建代理程式對象時候傳入的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 {    @Override    public int outPut(int num) {        System.out.println("outPut " + String.valueOf(num) + " people");        return num;    }    @Override    public 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 {    @Test    public void fun() {        ProxyFactory proxyfactory = new ProxyFactory();        // 代理的目標對象        proxyfactory.setTargetObject(new realSubject());        // 前置增強介面實現        proxyfactory.setBeforeAdvance(new BeforeAdvance() {            @Override            public void before() {                System.out.println("hello");            }        });        // 後置增強介面實現        proxyfactory.setAfterAdvance(new AfterAdvance() {            @Override            public 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, 參數為args        System.out.println(result);        System.out.println("-----");        Object result2 = subject2.outPut2(50);        System.out.println(result2);    }}輸出:hellooutPut 100 peoplebyebye100-----hellooutPut2 50 peoplebyebye50

在這裡面,只要使用反射,method.invoke()就可以調用代理的目標對象的該方法,然後實現前置增強BeforeAdvance介面和後置增強AfterAdvance介面,就可以實現對方法內容的增強了。
其中不同介面的不同實現方法都可以重用BeforeAdvance和AfterAdvance。
對於不同的增強對象也可以使用,只要targetObject改一下就可以了。

附上一篇講的不錯的文章

Java學習之動態代理

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.