java-代理設計模式(四)
代理設計模式
- 代理模式的基本結構
代理設計模式的核心思想就是:一個介面有若干個子類,其中有一個是真實主題類,負責真實的操作,要想完成這一功能必須有代理類負責,以學生上課和看門大爺為例:
觀察程式的執行:
package com.csii.wanghaoxin.demob;
interface Subject{
public void study();
}
class RealSubject implements Subject{
@Override
public void study() {
System.out.println("好好學習" );
}
}
class ProxySubject implements Subject{
private Subject subject;
public ProxySubject(Subject subject){
this.subject = subject;
}
public void open(){
System.out.println("開教室的門,並打掃");
}
public void close(){
System.out.println("趕學生離開,打掃衛生,關門");
}
@Override
public void study() {
this.open();
this.subject.study();
this.close();
}
}
class Factory{
public static Subject getInstance(){
return new ProxySubject(new RealSubject());
}
}
public class TestProxyDemo {
public static void main(String[] args) {
Subject sub = Factory.getInstance();
sub.study();
}
}
這個就是最原始的代理,但是需要知道的是可以有多層代理。
- 代理模式應用
現在就以核心的MVC設計模式為主,
傳統的模式會建立多個ServiceImpl以及多個DaoImpl,即業務邏輯層和資料庫處理層,但是有時候多個數據層的操作可能必須屬於同一個業務邏輯,即事務控制,需要事務控制:
於是進一步思考,一個專案中可能會有無數個業務層,那麼就意味著所有牽扯到資料更新的操作都會面臨著同樣的幾個步驟:
1.開啟資料庫
2.取消事務自動提交
3.進行資料層呼叫
4.手工處理事務
5.關閉資料庫
將輔助業務功能和核心業務功能進行區分,將基礎操作和核心業務分離
如果一個業務層就要有一個代理類和真實主題類,程式碼會很多,—-這是靜態代理。缺點”一個代理類只能為一個真是類服務
動態代理:能代理所有的操作
- 動態代理
如果按照之前的思路,假設說有500個業務層子類,那麼就需要準備出500個代理類,但是最重要的是500個代理類有何區別
如果要想使用動態代理類,就必須動態生成代理物件。它依靠真實主題類的物件介面定義生成。如果要想動態建立代理物件,則需要使用Proxy類
Proxy類核心方法
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
這個類定義有一個重要方法,根據指定真實主題類的介面動態建立一個代理類的物件操作。
引數的作用如下:
ClassLoader:取得真實主題的類載入器
Class<?>[] interfaces:真實主題類實現的所有介面
InvocationHandler h:代理設計的動態生成類,真正的代理結構定義的操作。
如果要定義動態代理類,那麼必須要實現InvocationHandler介面。在整個接口裡面定義有一個invoke的方法。
Object invoke(Object proxy,
Method method,
Object[] args)
throws Throwable
引數:Object Proxy:被代理的物件(代理物件)
Method method:要執行的操作方法:
Object[] args:方法所需要的引數
invoke方法完善後:
以後包括在面試之中,如果出現了代理設計模式的編寫, 寫出此程式,可以得到百分之八十的認同
切面設計+動態代理 更方便
- *CGLIB實現動態代理設計模式
不管是代理設計模式還是動態代理設計模式都會存在有一個致命問題,必須使用介面處理,包括動態代理也存在同樣的問題。
getInterfaces()
動態代理是依據物件所在類的介面來建立一個動態代理類物件進行操作的。但是哪裡有壓迫,哪裡就有反抗,於是又一類人提出了一個觀點:不用介面還要使用動態代理類。所以就產生了第三方的元件包:CGLIB元件,這個元件可以避免介面的使用,父類來進行代理操作。
可以通過sourceforce.net(sf.net)上下載CGLIB的開發包
CGLIB還是要使用動態代理設計的結構完成,如果不使用介面,則必須依靠另外一個抽象類來完成:
同時對於Proxy也需要更換為Enhancer。
範例:實現動態代理設計模式
雖然CGLIB的動態代理設計不依靠介面,但是必須要找到一個共同點,那麼就依靠類。
package com.wanghaoxin.demo;
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
class Messge{
public void print(){
System.out.println("Hello");
}
}
class ProxyImpl implements MethodInterceptor{
private Object target;//被代理的真實主題
public ProxyImpl(Object target){//儲存了真實主題類的物件
this.target = target;
}
@Override
public Object intercept(Object proxy, Method method, Object[] arg2, MethodProxy mproxy)
throws Throwable {
System.out.println("操作準備");
Object rev = method.invoke(this.target);
System.out.println("操作結束");
return rev;
}
}
public class TestProxyDemoC {
public static void main(String[] args) {
Messge msg = new Messge();
Enhancer eh = new Enhancer();//幫助使用者實現代理的工具類
eh.setSuperclass(Messge.class);//設定一個父類,這是一個模擬的過程
eh.setCallback(new ProxyImpl(msg));//操作的回撥過程
Messge mg = (Messge)eh.create();
mg.print();
}
}
- 總結
在實際開發中,代理設計模式最大的優點在於:完成輔助功能,本質上就是處理事務。
代理設計模式必須依靠介面存在,動態代理設計模式也同樣如此。
CGLIB開發包不需要介面實現動態代理