設計模式學習系列--代理模式

代理模式

一、代理模式(爲其他對象提供一種代理以便控制對這個對象的訪問)


代理組成:調用者,統一的接口,真實對象,代理類
原理:通過接口,實現這樣一個過程,在調用真實對象的時候,調用者並不直接與真實對象打交道,而是通過一個代理者與真實對象通信,代理者能夠負責真實對象的非業務邏輯,如日誌管理、訪問控制 、異常處理等,使得真實對象專注於業務邏輯的實現,不受非業務邏輯的干擾。

二、靜態代理實現

自己靜態定義代理類

2.1 統一接口

/**
 * 統一的接口
 * @author Administrator
 *
 */
public interface Subject {
	void request();
}

2.2 真實對象

/**
 * 真實對象
 * @author Administrator
 *
 */
public class RealSubject implements Subject {

	public void request() {
		System.out.println(" RealSubject excute request");
	}

}

2.3 代理對象

/**
 * 代理者
 * @author Administrator
 *
 */
public class Proxy implements Subject {
	
	private RealSubject realSubject;
	
	public Proxy(RealSubject realSubject){
		this.realSubject = realSubject;
	}
	
	public void request() {
		//植入的前置代碼
		System.out.println("####before##");
		try {
			realSubject.request();//真實對象執行的方法
			System.out.println("###after##");
		} catch (Exception e) {
			// TODO: handle exception
			System.out.println("####exception###");
		}finally{
			//植入的後置邏輯
			System.out.println("###finally##");
		}
	}

}

2.4客戶端調用

/**
 * 客戶端
 * @author Administrator
 *
 */
public class Client {
	public static void main(String[] args) {
		Subject subject = new Proxy(new RealSubject());
		subject.request();
	}
}

2.5 運行結果


總結:如果在接口中添加方法進行功能擴展,代理類需要重複寫對應接口的實現方法,增加重複性代碼,而且不利於維護和擴展

三、JDK實現的動態代理

3.1 動態代理

不需要自己是實現代理類,利用JDK的API,在內存中自動生成代理類,源碼探索:http://blog.csdn.net/shenbug/article/details/78960639

3.2 實現的要點

基於接口InvoctionHandler實現動態代理,由java.lang.reflect.Proxy實現代理類的創建

3.3 接口

/**
 * 統一的接口
 * @author Administrator
 *
 */
public interface Subject {
	void request();
}

3.4真實對象

/**
 * 真實對象
 * @author Administrator
 *
 */
public class RealSubject implements Subject {

	public void request() {
		System.out.println(" RealSubject excute request");
	}

}

3.5動態代理

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
 * JDK實現動態代理
 * @author Administrator
 *
 */
public class JdkProxy implements InvocationHandler{
	//目標對象
	private Object targetobject; 
	
	public JdkProxy(Object targetobject){
		this.targetobject = targetobject;
	}
	//綁定關係,也就是關聯到哪個接口(與具體的實現類綁定)的哪些方法將被調用時,執行invoke方法。
	public Object newProxyInstance(){
		//該方法用於爲指定類裝載器、一組接口及調用處理器生成動態代理類實例    
        //第一個參數指定產生代理對象的類加載器,需要將其指定爲和目標對象同一個類加載器  
        //第二個參數要實現和目標對象一樣的接口,所以只需要拿到目標對象的實現接口  
        //第三個參數表明這些被攔截的方法在被攔截時需要執行哪個InvocationHandler的invoke方法  
        //根據傳入的目標返回一個代理對象  
		return Proxy.newProxyInstance(targetobject.getClass().getClassLoader(), 
				targetobject.getClass().getInterfaces(), this);
	}
	/**
	 * @param proxy 被代理的對象
	 * @param method 要調用的方法
	 * @param args  方法調用所需要的參數
	 */
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		Object res = null;
		try {
			 /*原對象方法調用前處理信息*/  
			System.out.println("start");
			//調用目標方法
			res = method.invoke(targetobject, args);
		} catch (Exception e) {
			e.printStackTrace();
			/*原對象方法調用異常處理信息*/  
			System.out.println("error");
		}finally{
			/*原對象方法調用前處理信息*/  
			System.out.println("success");
		}
		return res;
	}

}

3.6 客戶端調用

public class Client1 {
	public static void main(String[] args) {
		//System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");  
		JdkProxy jdkProxy = new JdkProxy(new RealSubject());
		Subject subject = (Subject) jdkProxy.newProxyInstance();
		subject.request();
	}
}

3.7 測試


四、cglib實現動態代理

4.1 實現原理

1:生成指定類對象的子類,也就是重寫類中的業務函數。
2:執行回調函數,加入intercept()函數。
3:創建這個類的子類對象。
/**
 * cglib實現動態代理
 * @author Administrator
 *
 */
public class CglibProxy implements MethodInterceptor{
	
	//維護目標對象
    private Object target;

    public CglibProxy(Object target) {
        this.target = target;
    }
    //給目標對象創建一個代理對象
    public Object getProxyInstance(){
        //1.工具類
        Enhancer en = new Enhancer();
        //2.設置父類
        en.setSuperclass(target.getClass());
        //3.設置回調函數
        en.setCallback(this);
        //4.創建子類(代理對象)
        return en.create();

    }
	/**
	 * 添加植入的代碼
	 */
	public Object intercept(Object obj, Method arg1, Object[] arg2,
			MethodProxy proxy) throws Throwable {
		/*原對象方法調用前處理信息*/  
		System.out.println("####before####");
		Object result = null;
		try {
			//原對象方法調用
			result = proxy.invokeSuper(obj, arg2);
		} catch (Exception e) {
			// TODO: handle exception
			/*原對象方法調用異常處理信息*/ 
			System.out.println("#####exception#####");
		}finally{
			/*原對象方法調用後處理信息*/ 
			System.out.println("#####after####");
		}
		return result;
	}

}

4.2 客戶端調用

public class Client1 {
	public static void main(String[] args) {
		//System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");  
		JdkProxy jdkProxy = new JdkProxy(new RealSubject());
		Subject subject = (Subject) jdkProxy.newProxyInstance();
		subject.request();
	}
}

4.3 測試


五、jdk代理與cglib代理的對比


1.jdk基於接口實現代理,cglib基於繼承的方式實現代理
2.cglib不能代理static、final修飾的類
3.jdk只能實現代理實現接口類的方法







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