
代理類相當于是原本的類的class對象+自定義操作,了解為一層封裝。代理類主要負責為委托類預處理消息、過濾消息、把消息轉發給委托類,以及事後處理消息等。代理類的對象本身并不真正實作服務,而是通過調用委托類的對象的相關方法,來提供特定的服務。簡單的說就是,我們在通路實際對象時,是通過代理對象來通路的,代理模式就是在通路實際對象時引入一定程度的間接性,因為這種間接性,可以附加多種用途。
假如一個班的同學要向老師交班費,但是都是通過班長把自己的錢轉交給老師。這裡,班長就是代理學生上交班費,班長就是學生的代理。
靜态代理
由程式員建立或特定工具自動生成源代碼,也就是在編譯時就已經将接口,被代理類,代理類等确定下來。在程式運作之前,代理類的.class檔案就已經生成。
流程:
-
- 定義一個接口,定義了一個抽象方法。
- 被代理類實作了接口,重寫了方法。
- 代理類也實作接口,然後将被代理類引用,并通過構造方法引入,然後重寫方法,此時可以調用被代理類的方法
- main方法new了被代理類和代理類兩個對象,前者作為參數傳給後者,并調用後者的方法。
缺點:每個被代理類都要寫一個針對的代理類。
動态代理
代理類在程式運作時建立的代理方式被成為動态代理。動态代理的優勢在于可以很友善的對代理類的函數進行統一的處理,而不用修改每個代理類中的方法
若目标對象實作了接口,spring預設使用「JDK的動态代理」。
-
- 優點:因為有接口,是以使系統更加松耦合;
- 缺點:為每一個目标類建立接口;
若目标對象沒有實作任何接口,spring使用「CGLib動态代理」。
-
- 優點:因為代理類與目标類是繼承關系,是以不需要有接口的存在。
- 缺點:因為沒有使用接口,是以系統的耦合性沒有使用JDK的動态代理好。
「1、jdk動态代理」
newProxyInstance()會傳回一個實作了指定接口的代理對象,對該對象的所有方法調用都會轉發給InvocationHandler.invoke()方法。了解上述代碼需要對Java反射機制有一定了解。動态代理神奇的地方就是:
-
- 代理對象是在程式運作時産生的,而不是編譯期;
- 對代理對象的所有接口方法調用都會轉發到InvocationHandler.invoke()方法,在invoke()方法裡我們可以加入任何邏輯,比如修改方法參數,加入日志功能、安全檢查功能等;之後我們通過某種方式執行真正的方法體,可以通過反射調用對象的相應方法,還可以通過RPC調用遠端方法。
使用方法:代理類實作「InvocationHandler」,然後引用被代理類,并在構造方法裡傳入。然後重寫invoke方法,為具體操作代碼。然後通過
Proxy.newProxyInstance( getClass().getClassLoader(), new Class<?>[] {Hello.class}, // 2. 代理需要實作的接口,可以有多個
new LogInvocationHandler(new HelloImp()));// 3. 方法調用的實際處理者
Java動态代理是基于接口的,沒有實作接口該類無法使用JDK代理,CGLIB登場。
「2、CGLIB動态代理」
CGLib采用非常底層的位元組碼技術,可以為一個類建立子類,并在子類中采用方法去技術攔截所有的父類方法的調用,并順勢織入橫切邏輯。
目标對象:
//目标對象RealSubject,cglib不需要定義目标類的統一接口
public class RealSubject {
public void request() {
System.out.println("real subject execute request");
}
public void hello() {
System.out.println("hello");
}
}
代理對象:實作MethodInterceptor,重寫intercept方法。
//代理對象
public class DemoMethodInterceptor implements MethodInterceptor{
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("before in cglib");
Object result = null;
try{
result = proxy.invokeSuper(obj, args);
}catch (Exception e){
System.out.println("get ex:"+e.getMessage());
throw e;
}finally {
System.out.println("after in cglib");
}
return result;
}
}
用戶端調用:
//用戶端
public class Client {
public static void main(String[] args){
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(RealSubject.class);
enhancer.setCallback(new DemoMethodInterceptor());
// 此刻,realSubject不是單純的目标類,而是增強過的目标類
RealSubject realSubject = (RealSubject) enhancer.create();
realSubject.hello();
realSubject.request()
}
}
也可以通過匿名的方式:
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(SampleClass.class);
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("before method run...");
Object result = proxy.invokeSuper(obj, args);
System.out.println("after method run...");
return result;
}
});
SampleClass sample = (SampleClass) enhancer.create();
sample.test();
}