博主專注於Java、架構、Linux、小程序、爬蟲、自動化等技術。 工作期間含淚整理出一些資料,微信搜索【程序員高手之路】,回覆 【java】【黑客】【爬蟲】【小程序】【面試】等關鍵字免費獲取資料
前言
先贊後看,此生必賺!
Java中動態代理的實現,主要是InvocationHandler和Proxy的使用。
可以通過以下步驟實現一個動態代理:
一、創建正常的接口以及實現類
1. 接口:
public interface People {
public void working();
}
2. 實現類:
public class Student implements People {
@Override
public void work() {
System.out.println("正在學習...");
}
}
二、創建一個PeopleHandler實現InvocationHandler
public class PeopleHandler implements InvocationHandler {
private Object obj;
public PeopleHandler(Object obj) {
this.obj = obj;
}
public Object getProxy(Object obj) {
return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("before invoke...");
Object result = method.invoke(obj, args);
System.out.println("after invoke...");
return result;
}
}
解讀:
PeopleHandler(Object obj):通過被代理對象創建handler;
getProxy(Object obj):通過被代理對象創建代理;
invoke(Object proxy, Method method, Object[] args):代理不直接調用invoke,而是使用正常的方法時都會走invoke方法;
三、調用方法
可以使用兩種方式調用方法:
1. 直接調用
不使用代理類直接調用,直接實現業務邏輯
2. 使用代理類調用
使用代理類調用,間接實現業務邏輯
public class TestProxy {
public static void main(String[] args) {
//1.直接調用
System.out.println("直接調用:");
People people = new Student();
people.work();
//2.通過代理調用
System.out.println("\n通過代理調用:");
PeopleHandler handler = new PeopleHandler(people);
People proxy = (People) handler.getProxy(people);
proxy.work();
}
}
結果:
直接調用:
正在學習...
通過代理調用:
before invoke...
正在學習...
after invoke...
四、總結
1. 使用代理的好處
從上面的案例可以看出,兩者都可以實現正常的業務邏輯,那爲啥要多此一舉地使用代理類呢?
1.1 降低耦合度
正常邏輯work()與日誌的關係沒那麼強烈,可以對業務邏輯的各個部分進行隔離。
1.2 提高可重用性
如果不使用代理,需要每一次在調用work()前後都要寫日誌,這樣的話,代碼的可重用性爲0!
使用代理之後,只需要在handler的invoke()方法中寫一次即可,重用性明顯提高!
2. 使用場景
除了上面案例中的日誌,還有性能統計,安全控制,事務處理,異常處理等等。
安全控制舉例:
校驗用戶權限,每一個菜單請求,都要判斷一下請求的用戶是否有該菜單權限。菜單多了,代碼冗餘,且容易遺漏。
通過動態代理就可以實現爲:每一個用戶,每一個菜單的請求,都經過代理(proxy),由他判斷是否有權限,調用者只需要調用,實現自己的邏輯,不關心權限問題。