Java 動態代理機制 — java.lang.reflect

在 java.lang.reflect包中除了與Java反射相關的類,還提供了動態代理運行機制。代理是基本的設計模式之一,它是你爲了提供額外的或者不同的操作,而插入的用來代替實際對象的對象。這些操作通常設計與實際對象的通信,因此代理通常充當着中間人的角色。

如下:有一個名稱爲Interface的接口,裏面定義了兩個方法,並且RealObject實現了Interface接口:

public interface Interface {
    void doSomethings();
    void doElseThings();
}
public class RealObject implements Interface {
    public RealObject() {	
    }
    public void doSomethings() {
        System.out.println("doSomething");
    }
    public void doElseThings() {
	System.out.println("doElseThings");
    }
}

我們一般情況下會使用new創建一個對象Interface interface = new RealObject(),interface .doSomethings()執行方法。但是如果我們想要在執行接口Interface裏定義的方法之前或者之後做一些其他事情,這個時候直接調用doSomethings就不行了,所以我們此刻需要創建一個代理類去執行:

public class SimpleProxy implements Interface {
    private Interface target;
    public SimpleProxy(Interface target) {
        this.target = target;
    }
    public void doSomethings() {
	System.out.println("開始執行doSomethings方法");
	target.doSomethings();
	System.out.println("執行doSomethings方法結束");
    }
    public void doElseThings() {
	System.out.println("開始執行doElseThings方法");
	target.doElseThings();
	System.out.println("執行doElseThings方法結束");
    }

}

如上面我們創建了一個代理類,我們在執行Interface接口的方法時,不需要直接調用其實現類的方法,而是調用代理類的方法,並且可以在代理類中做一些額外的操作。

public class SimpleProxyDemo {	
    public static void main(String[] args) {
	SimpleProxy simpleProxy = new SimpleProxy(new RealObject());
	simpleProxy.doSomethings();
	System.out.println();
	simpleProxy.doElseThings();
    }
}

其實上面的例子是一個經典的靜態代理的示例,使用靜態代理如果有多個接口或者類需要使用動態代理的方式去調用,這個時候我們不得不創建多個代理類,還好Java爲我們提供了動態代理機制。靜態代理類需要我們實現要代理的接口定義,Java的動態代理機制需要代理類實現java.lang.reflect.InvocationHandler接口,如下我們創建一個最簡單的動態代理類:

public class ProxyHandler<T> implements InvocationHandler {
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		System.out.println("開始執行方法");
		System.out.println("執行方法結束");
		return "調用結果";
	}
}

創建了代理類之後,就是如何將代理類與需要代理的對象聯繫起來,我們使用Java 中的java.lang.reflect.Proxy去創建一個被代理的實例。代碼如下:

public class DynamicProxyFactory<T> {
	
    public static <T> T newInstance(Class<T> mapperInterface ) {
        T newProxyInstance = (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, new ProxyHandler<T>());
        return newProxyInstance;
    }
}

Proxy使用其靜態方法public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)實例化一個接口,接口參數爲ClassLoader 類加載器,接口類型和一個代理類(真正被調用的類的)

public class DynamicProxyTest {
    public static void main(String[] args) {
       DynamicProxyFactory dynamicProxy = new DynamicProxyFactory();
        //實例化一個接口,該接口沒有任何實現類
	Tickets tickets = (Tickets) dynamicProxy.newInstance(Tickets.class);
	System.out.println("調用接口返回 :" + tickets.buyTickets());
        //實例化一個接口,該接口沒有任何實現類
	Insurance insurance = (Insurance) dynamicProxy.newInstance(Insurance.class);
	System.out.println("調用接口返回 :" + insurance.buyInsurance());
	}
}

使用動態代理,我們無需實現類就可以實例化一個接口,並且調用接口中定義的方法,我們在調用接口的方法時,其實調用的是ProxyHandler的invoke方法。

反射包是大多數框架的基礎,包括代理模式,Mybatis中就使用了動態代理模式,使得在寫Mapper時,我們只需要定義Mapper接口而不需要實現Mapper接口,即可以查詢數據庫。後續MyBatis學習中會介紹MyBatis中的動態代理的實現方式,自己有興趣的話,也可以自己去查看MyBatis源碼。MyBatis中的動態代理的實現在org.apache.ibatis.binding包中實現的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章