代理模式
一、代理模式(爲其他對象提供一種代理以便控制對這個對象的訪問)
代理組成:調用者,統一的接口,真實對象,代理類
原理:通過接口,實現這樣一個過程,在調用真實對象的時候,調用者並不直接與真實對象打交道,而是通過一個代理者與真實對象通信,代理者能夠負責真實對象的非業務邏輯,如日誌管理、訪問控制 、異常處理等,使得真實對象專注於業務邏輯的實現,不受非業務邏輯的干擾。
二、靜態代理實現
自己靜態定義代理類
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只能實現代理實現接口類的方法
3.jdk只能實現代理實現接口類的方法