java中的代理和動態代理講解

在說到動態代理模式,我們首先說一說什麼是代理模式。

  • 什麼是代理模式:

Proxy Pattern(即:代理模式)23種常用的面向對象軟件的設計模式之一

代理模式的定義:這裏先舉一個例子,假設某人要找對象,但是由於某些原因不能直接去找,於是委託一箇中介機構去完成這一

過程,如婚姻介紹所,在這裏婚姻介紹所其實就是一個代理。再舉一個專業相關的例子,如果你想調用一個功能非常強大的加密

算法,而現在正在開發的系統又需要使用到該算法,由於該算法位於遠程服務器端,封裝該算法的對象位於遠程服務器內存中,

本地內存中的對象無法直接訪問,因此需要通過一個遠程代理的機制來實現遠程對象的操作。也其實也就是webservice、

httpclient等實現原理。再看代理的定義:給某一個對象提供一個代理,並有代理對象控制對原對象的引用。

優點:

(1).職責清晰

真實的角色就是實現實際的業務邏輯,不用關心其他非本職責的事務,通過後期的代理完成一件完成事務,附帶的結果就是編程

簡潔清晰。

(2).代理對象可以在客戶端和目標對象之間起到中介的作用,這樣起到了的作用和保護了目標對象的作用。

(3).增強代碼的拓展性

結構

一個是真正的你要訪問的對象(目標類)一個是代理對象,真正對象與代理對象實現同一個接口先訪問代理類並通過代理對象

來訪問真正要訪問的對象中的方法。


簡單案例

在一個論壇中已註冊用戶和遊客的權限不同個,已註冊的用戶擁有發帖、修改自己的註冊信息、修改自己的帖子等功能;

而遊客只能看到別人發的帖子,沒有其他權限。在這裏我們使用代理模式來設計權限管理模塊。

(1)抽象主題類

public interface AbstractDemo {
	
	public void function();
	

}
AbstractDemo作爲抽象權限類,充當了抽象主體角色,在其中聲明瞭真實主題角色所提供的業務方法,它是真是主題角色和代理

主題角色的公共接口。這裏所說的主題角色就是需要被代理的對象

(2)真實主題類(需要被代理的類)

public class RealDemo implements AbstractDemo {

	@Override
	public void function() {

		System.out.println("一種算法");
	}


RealDemo是真實主題角色,它實現了在抽象主題角色中定義的方法,假設由於種種原因,客戶端無法直接訪問其中的方法。

(3)代理主題角色

public class DemoProxy implements AbstractDemo {
	
	private RealDemo demo = new RealDemo();
	@Override
	public void function() {
		demo.function();
	}

}

這樣我們就用DemoProxy代理了RealDemo,並使用了RealDemo的function方法。

(4)最後再客戶端調用

      public static void main(String[] args) {
		
		AbstractDemo demo = new DemoProxy();
		demo.function();
	}


  • 動態代理模式
在上述的代理模式不知道大家有沒有注意到一些問題,1、就是如果DemoProxy要想調用RealDemo中的function方法,
首先這個真實主題角色也就是RealDemo必須存在。2、如果一個真實角色對應一個代理主題角色,這將導致系統中類的數量
急劇增加。上述兩個問題都是動態代理需要解決的問題。

接下來我們重複代理模式的過程,看看動態代理是怎樣解決的

(1)抽象主題類

package demo;

public interface AbstractDemo {
	
	public void function(int i);
}

(2)真實主題類一(需要被代理的類)

public class RealDemo1 implements AbstractDemo {

	@Override
	public void function(int i) {
		
		System.out.println("一種加密算法"+i);
	}

}
(3)真實主題類二(需要被代理的類)

public class RealDemo2 implements AbstractDemo {

	@Override
	public void function(int i) {
		
		System.out.println("一種解密算法"+i);
	}

}
(4)動態代理的實現過程

class TestDemo {

	public static void main(String[] args) {
		
		final AbstractDemo demo1 = new RealDemo1();
//		Proxy.newProxyInstance():產生代理類的實例。僅能代理實現至少一個接口的類
//		ClassLoader:類加載器。也可以寫成demo.getClass().getClassLoader()。
//		Class[] interface:代理類要實現的接口。固定寫法,和被代理類使用相同的接口即可。
//		InvocationHandler:策略(方案)設計模式的應用。如何代理?
		AbstractDemo proxy = (AbstractDemo)Proxy.newProxyInstance(AbstractDemo.class.getClassLoader(), 
				new Class[]{AbstractDemo.class}, new InvocationHandler() {
//			  InvocationHandler中的invoke方法:調用代理類的任何方法,此方法都會執行	
//			  Object proxy:代理對象本身的引用。一般用不着。
//			  Method method:當前調用的方法。
//			  Object[] args:當前方法用到的參數				
					@Override
					public Object invoke(Object proxy, Method method, Object[] args)
							throws Throwable {
						System.out.println("執行方法前");
						Object obj =  method.invoke(demo1,new Object[]{(int)args[0]});
						System.out.println("執行方法後");
						return obj;
					}
				});
		proxy.function(2);
	}
}

結果如下:

執行方法前
一種算法2
執行方法後

上面代碼的註解非常詳細,如果大家認真閱讀,應該對動態代理應該明白的差不多了。閱讀上面代碼,動態代理可以動態地

代理你說需要代理的對象,這裏我們代理的是RealDemo1對象。如果我們想代理RealDemo2對象,那麼我們只要首先實例RealDemo2對象

,得到demo2,然後method.invoke(demo1,new Object[]{args[0]});中的demo1改成demo2即可。這樣這個動態代理就可以代理很多主

題類,那麼系統的類就不會急劇增加了。


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