在上篇博客中,我們說到了代理模式的一種形式——靜態代理,文章結尾處提到了靜態代理的不足之處,其中有一個就是當我們的業務類非常多的時候,還用靜態代理顯然是一個非常糟糕的選擇,那麼這種情況該如何解決呢?這就引出了我們的動態代理。
什麼是動態代理?
所謂的動態代理是相對於靜態代理來講的,利用反射機制,在程序的運行期決定加載哪個類,很好的規避了靜態代理一個業務類對應一個代理類的問題。
為何用動態代理?
使用動態代理是為了解決靜態代理的擴展性差和維護困難的問題,這個在文章開頭就說的很明白了,
如何用動態代理?
要想使用動態代理,就必須使用Proxy(代理類)和InvocationHandler(反射)兩個東西了。我接著使用上篇博客的例子為大家說明如何使用動態代理。
用戶管理的接口和實現就不再贅述了,下面請直接看動態代理類LogHandler和客戶端的代碼:
模擬日志功能的動態代理對象類LogHandler。代碼如下:
public class LogHandler implements InvocationHandler { //目標對象 private Object targetObject; /** * 該類的實例化方法,用於將目標對象傳入 * @param targetObject 目標對象 * @return */ public Object newProxyInstance(Object targetObject) { this.targetObject = targetObject; //調用Proxy類的靜態方法newProxyInstance實例化一個代理類,並且將目標對象作為參數傳入 return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(), targetObject.getClass().getInterfaces(), this); } /** * 執行目標對象的方法 */ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //在目標對象的方法執行之前打印一下 System.out.println("開始執行方法-->>" + method.getName()); for (int i=0; i
客戶端:
public class Client { /** * @param args */ public static void main(String[] args) { //實例化動態代理類LogHandler LogHandler logHandler = new LogHandler(); //將用戶管理實現類傳入動態代理類 UserManager userManager = (UserManager)logHandler.newProxyInstance(new UserManagerImpl()); //userManager.addUser("0001", "鐘躍民"); //userManager.delUser("0001"); String name = userManager.findUser("0001"); System.out.println("Client.main() --- " + name); } }
小結一下:
動態代理與靜態代理相比較,最大的好處是接口中聲明的所有方法都被轉移到調用處理器一個集中的方法中處理(InvocationHandler.invoke)。這樣,在接口方法數量比較多的時候,我們可以進行靈活處理,而不需要像靜態代理那樣每一個方法進行中轉。而且動態代理的應用使我們的類職責更加單一,復用性更強。
無論是靜態代理和是動態代理,這種代理的思想,是十分有指導意義的。很多的框架和技術,都有代理的影子。比如Spring中的AOP(面向切面編程)的本質就是代理模式,還有SSH框架中的每一個框架都使用了代理模式。