Java中使用代理的作用是對目标對象的增強,在實際中我們可以在執行目标方法前後進行一些必要的處理。
1.靜态代理
靜态代理比較容易了解,我們直接給出例子。比如我們的目标方法是request方法,但是我們希望在每次調用request方法前都進行處理,如列印日志,那麼久需要使用代理來處理。
接口
public interface Subject{
public void request();
}
目标類
class SubjectImpl implements Subject{
public void request(){
System.out.println("I am dealing the request.");
}
}
靜态代理類
在靜态代理類中我們接受實際的目标對象,并且在目标方法前後可以進行處理。
class StaticProxy implements Subject{
//實際目标對象
private Subject subject;
public StaticProxy(Subject subject){
this.subject = subject;
}
public void request(){
System.out.println("PreProcess");
subject.request();
System.out.println("PostProcess");
}
}
測試方法
在我們調用p.request()方法的時候則會列印出目标方法前後的資訊
public class StaticProxyDemo {
public static void main(String args[]){
//建立實際對象
SubjectImpl subject = new SubjectImpl();
//把實際對象封裝到代理對象中
StaticProxy p = new StaticProxy(subject);
p.request();
}
}
總結:靜态代理的優缺點很明顯,優點是代碼簡單,缺點是當目标對象有多個方法時,我們要對每個方法都進行處理,是以會非常繁瑣。
2.動态代理
動态代理克服了靜态代理的缺點,在動态代理中,目标對象的方法每次被調用都進行動态攔截。
簡單解釋一下下面的圖:用戶端每次調用都是代理對象的方法,不可能直接調用目标對象的方法,所有的調用方法都會被攔截下來,轉發給代理處理器的invoke方法進行處理,在代理處理器的invoke方法中我們可以判定該方法是什麼方法,有什麼參數。最後再調用目标對象的真實方法來進行工作,真實方法執行結束以後,一路傳回執行結果。
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsICM38FdsYkRGZkRG9lcvx2bjxiNx8VZ6l2cs0TTXVmZ5cVWv50MMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2X0hXZ0xCMx81dvRWYoNHLrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnL4AzN4QzMwYTM5EzMwAjMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
下面舉例
接口和目标類與靜态代理的相同
接口
public interface Subject {
public void request();
}
目标類
public class SubjectImpl implements Subject {
@Override
public void request() {
System.out.println("I am dealing the request.");
}
}
代理處理器
/*
* 代理處理器,實作了InvocationHandler接口
* */
public class ProxyHandler implements InvocationHandler {
//持有目标對象的句柄
private Subject subject;
public ProxyHandler(Subject subject){
this.subject = subject;
}
/*
* invoke()方法
* 此方法在代理對象調用任何一個方法時都會被調用
*
* 第一個參數:proxy 代理對象
* 第二個參數:method 反射裡面的Method類,檢視具體調用哪個方法
* 第三個參數:args 具體的形參
* */
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
//輸出代理類的名字
System.out.println(proxy.getClass().getName());//代理對象所屬的類是虛拟機自動生成的
//定義預處理工作,當然也可以根據method的不同進行不同的預處理工作
System.out.println("=========before========");
//調用真實的目标對象來進行工作
Object result = method.invoke(subject, args);
System.out.println("=========before========");
return result;//傳回結果
}
}
測試類
//動态代理模式
public class TestDynamicProxy {
public static void main(String[] args) {
//1.建立目标對象
final Subject subject = new SubjectImpl();
//2.建立代理處理器對象
ProxyHandler proxyHandler = new ProxyHandler(subject);
//3.動态生成代理對象
Subject proxySubject = (Subject) Proxy.newProxyInstance(
subject.getClass().getClassLoader(), //類加載器
subject.getClass().getInterfaces(), //具體的接口
proxyHandler); //代理對象需要代理處理器對象,代理處理器重寫了invoke方法
//4.用戶端通過代理對象調用方法,本次調用将自動地被代理處理器的invoke方法接收
proxySubject.request();
System.out.println(proxySubject.getClass().getName());
}
}
測試結果:
com.sun.proxy.$Proxy0是代理對象所屬的類,它是由虛拟機自動生成的。
對代理處理器 的了解:
代理處理器持有目标對象的句柄,并實作InvocationHandler接口
- 主要是實作了invoke方法
- 所有的代理對象方法調用,都會轉發到invoke方法來
- invoke的形參method,就是指代理對象方法的調用
- 在invoke内部,可以根據method,使用目标對象不同的方法來響應請求