1.代理模式
在代理模式中,接活的就是代理,實際干事兒的就是被代理的對象,也就是說,接活的和干活的不是同一個對象。
這裡舉經典的火車站和火車票代售點為例來說明。
package testproxy; public interface SellTicket { public void sellTicket(); }SellTicket接口只有一個賣票的方法,凡是實現了該接口的類,都有賣票的能力。首先,火車站有賣票的能力:
package testproxy; public class RailwayStation implements SellTicket { @Override public void sellTicket() { System.out.println(火車站售票); } }然後,火車票代售點有賣票的能力:
package testproxy; public class RailwayStationProxy implements SellTicket { SellTicket sellTicket; public RailwayStationProxy() { this.sellTicket = new RailwayStation(); } @Override public void sellTicket() { System.out.println(開始售票); this.sellTicket.sellTicket(); System.out.println(售票成功); } }與火車站不同的是,火車票代售點自己並沒有票,實際上出票的是火車站。可見,代售點只是個接活的,也就是代理,火車站才是真正干活的對象,也就是被代理的對象。
下面是一個買票的客戶:
package testproxy; public class Client { public static void main(String[] args) { SellTicket sellTicket = new RailwayStationProxy(); sellTicket.sellTicket(); } }客戶買票的過程是這樣的:
開始售票
火車站售票
售票成功
可見,代理參與了售票活動,但是真正出票的是火車站。
總結一下代理模式:代理和被代理對象都向外宣稱自己有干某件事的能力,供客戶調用,所以它們必須繼承同一個接口;但是,代理並沒有真正干某件事兒的能力,所以,他需要有一個對被代理對象的引用,當客戶讓它干事兒時,它就讓被代理對象去干。
2.JDK動態代理
JDK動態代理讓我們不用創建代理類就能創建一個代理對象。
代理對象是通過java.lang.reflect.Proxy類的靜態方法創建的:
newProxyInstance(ClassLoader loader,Class[] interfaces,InvocationHandler h)
它的參數分別是類加載器、宣稱該代理有哪些能力的接口的Class數組和一個調用處理器。類加載器用於加載接口;調用處理器用於關聯代理對象和被代理對象。調用處理器有下面這個方法:
invoke(Object proxy, Method method, Object[] args)
proxy是代理對象,method是客戶端調用的代理對象的方法對應的Method對象,args是客戶端傳給調用方法的參數。客戶端每次調用代理對象上的方法,都會觸發調用處理器的invoke方法被調用。
這裡同樣用火車站和火車票代售點的例子來具體說明:
同樣有一個用於宣稱代理對象和被代理對象有何能力的接口:
package testproxy; public interface SellTicket { public void sellTicket(); }
package testproxy; public class RailwayStation implements SellTicket { @Override public void sellTicket() { System.out.println(火車站售票); } }
package testproxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class SellTicketHandler implements InvocationHandler { private Object target; public SellTicketHandler(Object target) { super(); this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println(開始售票); method.invoke(target); System.out.println(售票成功); return null; } }
接下來是在客戶端,在客戶端創建代理對象,並調用它上面的方法:
package testproxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class DynamicProxy { public static void main(String[] args) { RailwayStation railwayStation = new RailwayStation(); InvocationHandler handler = new SellTicketHandler(railwayStation); Class[] interfaces = new Class[] {SellTicket.class}; Object proxy = Proxy.newProxyInstance(handler.getClass().getClassLoader(), interfaces, handler); try { Method method = SellTicket.class.getMethod(sellTicket); method.invoke(proxy); } catch (NoSuchMethodException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (SecurityException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InvocationTargetException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
開始售票
火車站售票
售票成功
最終總結:不管是代理模式,還是JDK的動態代理,都有這樣幾個元素:代理,被代理對象,以及宣稱它們能力的接口;只是動態代理不需要顯示創建代理類。