最近學習到設計模式,現總結個人學習代理模式内容【更加關注過程,對被代理對象完全控制】。
上一篇:Java設計模式-委派模式
文章目錄
- 定義
- 優缺點
-
- 優點
- 缺點
- 實作
-
- CGLIB代理
-
- 代碼
- 測試
- JDK代理
-
- 代碼
- 測試
- 對比
定義
為其他對象提供一種代理以控制對這個對象的通路。在某些情況下,一個對象不适合或者不能直接引用另一個對象,而代理對象可以在用戶端和目标對象之間起到中介的作用
優缺點
優點
- (1).職責清晰,不用關心其他非本職責的事務。
- (2).代理對象可以在用戶端和目标對象之間起到中介的作用,這樣起到了中介的作用和保護了目标對象的作用。
- (3).高擴充性 [1]
缺點
- 需要重新建立不可見對象。達到重寫的目的。
- 使用到了反射,降低了性能。
實作
CGLIB代理
代碼
代理對象需要實作MethodInterceptor,屬于cglib.jar包。
cglib内部建立一個對象,繼承我們的對象[LoginWorkflow ],在建立的對象上重寫了父類的方法,但是還是會使用父類的邏輯,而代理代碼,則在業務邏輯前後添加其他業務邏輯。
/**
* 登入流程
* @author cc百川
*/
public class LoginWorkflow {
public String doSubmit(){
System.out.println("正在登入");
return "登入成功";
}
}
public class ProxyLog implements MethodInterceptor{
public Object install(Class clazz) throws Exception{
Enhancer enhancer = new Enhancer();
//告訴cglib,生成的子類需要繼承哪個父類
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);//設定回調,告訴繼續執行業務代碼的類
//生成源代碼,編譯成class檔案,加載到JVM中,并傳回被代理對象
return enhancer.create();//建立被代理對象
}
@Override
public Object intercept(Object obj, Method arg1, Object[] arg2,
MethodProxy proxy) throws Throwable {
System.out.println("代理登入前處理業務邏輯,判斷是否規定時間登入");
//該obj的引用是由CGLib給我們new出來的,這個是被代理對象的子類,子類引用強轉父類,這時就可以操作父類的屬性
String res = (String) proxy.invokeSuper(obj, arg2);
System.out.println("代理登入後處理日志相關等");
return res+",代理添加了日志";
}
}
測試
JDK代理
代碼
jdk代理核心實作InvocationHandler。
jdk代理需要借助接口,也就是被代理者實作一個接口【這裡是Workflow】。
jdk實作代理過程
- 1.拿到被代理對象的引用,然後擷取它的接口
- 2.JDK代理重新生成一個類,同時實作我們給的代理對象所實作的接口
- 3.把被代理對象的引用也拿到了
- 4.重新動态生成一個class位元組碼
- 5.然後編譯
/**
* 流程送出
* @author cc百川
*/
public interface Workflow {
String doSubmit();
}
/**
* 登入流程
* @author cc百川
*/
public class LoginWorkflow implements Workflow{
public String doSubmit(){
System.out.println("正在登入");
return "登入成功";
}
}
/**
* 代理登入 jdk代理核心實作InvocationHandler
* @author cc百川
*/
public class ProxyLog implements InvocationHandler{
//用于保留被代理對象的引用
private Workflow wf;
//擷取被代理的對象【資料】
public Object install(Workflow wf) {
this.wf = wf;
Class cs = wf.getClass();
return Proxy.newProxyInstance(cs.getClassLoader(), cs.getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("代理登入前處理業務邏輯,判斷是否規定時間登入");
String res = (String) method.invoke(this.wf, args);//執行原業務邏輯
System.out.println("代理登入後處理日志相關等");
return res+",代理添加了日志";
}
}
測試
通過代理的方式,可以在執行業務代碼前後添加邏輯
對比
JDK的動态代理是通過接口來進行強制轉換的,生成以後的代理對象,可以強制轉換為接口。
CGLib的動态代理是通過生成一個被代理對象的子類,然後重寫父類的方法。子類引用強轉給父類【被代理類】,進而調用對象方法。
日常對代理模式,常見有AOP,以及産品二開等,達到無侵入修改【後期舉例】。
以上僅為個人學習,如果錯誤望指出,謝謝。