【菜鳥學Java】13:代理模式——動態代理這樣玩!

連江偉發表於2016-02-23

        在上篇部落格中,我們說到了代理模式的一種形式——靜態代理,文章結尾處提到了靜態代理的不足之處,其中有一個就是當我們的業務類非常多的時候,還用靜態代理顯然是一個非常糟糕的選擇,那麼這種情況該如何解決呢?這就引出了我們的動態代理。

        什麼是動態代理?

        所謂的動態代理是相對於靜態代理來講的,利用反射機制,在程式的執行期決定載入哪個類,很好的規避了靜態代理一個業務類對應一個代理類的問題。

        為何用動態代理?

        使用動態代理是為了解決靜態代理的擴充套件性差和維護困難的問題,這個在文章開頭就說的很明白了,

        如何用動態代理?

        要想使用動態代理,就必須使用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<args.length; i++) {
			System.out.println(args[i]);
		}
		Object ret = null;
		try {
			
			//呼叫目標物件的方法
			ret = method.invoke(targetObject, args);
			
			//在目標物件的方法執行之後列印一下
			System.out.println("方法執行完畢!-->>" + method.getName()); 
		}catch(Exception e) {
			e.printStackTrace();
			System.out.println("方法執行出錯!-->>" + method.getName());
			throw e;
		}
		return ret;
	}

}

        客戶端:

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框架中的每一個框架都使用了代理模式。

相關文章