java 代理模式詳解
前言:
在某些情況下,一個客戶不想或不能直接引用一個對象,此時可以透過一個稱之為「代理」的第三者來實現間接引用。代理對象可以在客戶端和目標對象之間起到 中介的作用,並且可以透過代理對象去掉客戶不能看到 的內容和服務或添加客戶需要的額外服務。
簡單來說代理模式就是透過一個代理對象去存取一個實際對象,並且可以像裝飾模式一樣為對象添加一些功能。
靜態代理
所謂靜態代理即在程式運行前代理類別就已經存在,也就是說我們編寫程式碼的時候就已經把代理類別的程式碼寫好了,而動態代理程式則是在程式運行時自動生成代理類。
描述太過抽象,看一下程式碼就明白是怎麼回事了
main
public class Main { public static void main(String[] args) { Water water = new Water(); WaterProxy waterProxy = new WaterProxy(water); waterProxy.drink(); } }
介面
//代理类与被代理类共同实现的接口 public interface Drink { void drink(); }
代理類
//被代理的类 public class Water implements Drink { @Override public void drink() { System.out.println("drink water"); } }執行結果
//代理类 //与被代理类实现同一个接口 public class DrinkProxy implements Drink { private Drink drinkImpl; //通过构造函数传入Water对象 public DrinkProxy(Drink drinkImpl) { this.drinkImpl = drinkImpl; } @Override public void drink() { //在执行被代理对象的方法前做一些事情 System.out.println("before drink"); //执行被代理对象的方法 drinkImpl.drink(); //在执行被代理对象的方法后做一些事 System.out.println("after drink"); } }動態代理有時鐵打的代理類,流水的被代理類。而採用靜態代理就只能代理實作了同一介面的類,如果要代理任意類則必須寫很多重複的代理類。此時我們可以採用動態代理,Java已經為實作動態代理提供了一套比較方便的工具。 java.lang.reflect.Proxy類別中可以動態產生代理物件的方法
before drink drink water after drinkInvocationHandler介面
/** *返回实现了指定接口的对象,调用代理对象的方法会调用 *InvocationHandler的invoke方法 * * @param loader 获取代理类所使用的类加载器 * @param interfaces 代理类所要实现的接口 * @param h 实现了InvocationHandler接口的对象 * @return 代理对象 */ public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces, InvocationHandler h)InvocationHandler介面的實作類別
/** *每个代理类都有一个关联的InvocationHandler *当代理对象执行一个方法的时候会直接执行invoke方法 */ public interface InvocationHandler { /** * @param 调用该方法的代理对象 * @param method 代理对象所调用的方法 * @param args 调用的方法的参数 * @return 调用的方法的返回值 */ public Object invoke(Object proxy, Method method, Object[] args) }Main
public class CommonInvocationHandler implements InvocationHandler { //被代理的对象 private Object proxied; public CommonInvocationHandler(Object proxied) { this.proxied = proxied; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //在调用被代理对象的方法前做一些事情 System.out.println("before doing something"); //调用被代理对象的方法 Object result = method.invoke(proxied, args); //在调用被代理对象的方法后做一些事情 System.out.println("after doing something");; return result; } }
public class Main { public static void main(String[] args) { //被代理的对象 Water water = new Water(); //动态获取代理对象 Drink waterProxy = (Drink) Proxy.newProxyInstance(water.getClass().getClassLoader(), water.getClass().getInterfaces(), new CommonInvocationHandler(water)); //通过代理对象调用方法 waterProxy.drink(); } }被代理對象,但是必須有相應的接口(沒有實現接口的類別可以使用cglib實現動態代理)才可以動態取得代理物件。像最近比較火的Retrofit就直接透過聲明好的介面使用動態代理進行網路請求。 範例簡單的模擬一下retrofitPOST注 Main
before doing something drink water after doing something感謝閱讀,希望能幫助大家,謝謝大家對本站的支持! 更多Java中的代理模式詳解及實例代碼相關文章請關注PHP中文網!