代理模式是設計模式的一種。動態代理的特點就是編譯階段不生成代理類,運行時生成代理類。常見的動態代理有兩種,JDK動態代理和CGLIB動態代理。JDK動態代理是基於反射機制實現的,cglib動態代理是基於asm實現的
jdk動態代理的實現
jdk動態代理主要需要用到InvocationHandler接口和Proxy類,都在java.lang.reflect包中每一個動態代理類都需要實現InvocationHandler
這個接口,並重寫invoke(proxy, method,args[])方法,invoke方法中在邏輯代碼的前後可以加上我們想要的其他邏輯
/**
* JDK動態代理
*/
// 接口
public interface Factory {
String sellProduct(String name);
}
// 實現類
public class Market implements Factory {
@Override
public String sellProduct(String name) {
System.out.println("成本價1000");
return "";
}
}
// 代理類
public class ZhongJianShang implements InvocationHandler {
private Object target;
public void setTarget(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 加強操作
System.out.println("我是中間商,我要賺1000差價");
// 調用原方法
Object result = method.invoke(target, args);
//加強操作
System.out.println("便宜點,2000賣你");
return result;
}
// 這個方法返回的是代理對象實例,返回代理類的方法不一定寫在這裏,可以寫在一個工廠方法中
public Object CreateProxyObject() {
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
}
// 測試
public class test {
public static void main(String[] args) {
Factory factory = new Market();
ZhongJianShang zjs = new ZhongJianShang();
zjs.setTarget(factory);
Object obj = zjs.createProxyObject();
factory = (Factory) obj;
factory.sellProduct("手機");
}
}
- jdk動態代理的特點:
JDK動態代理需要被代理類實現一個接口,所以不實現接口的類無法被動態代理,並且增強的方法只能是重寫的接口中的方法(因爲jdk動態代理是通過反射機制生成代理接口的匿名類,且該匿名類已經繼承Proxy類,不能再繼承其他類,實現交互獲取方法只能通過接口,也因此增強的方法只能是接口中聲明過的方法)
cglib動態代理的實現
cglib動態代理的類不需要實現任何接口,只需要實現MethodInterceptor
接口並重寫intercept方法即可
public class Market {
public String sellProduct(String name) {
System.out.println("成本價1000");
return "";
}
}
public class CglibZhongJianShang implements MethodInterceptor {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("我是中間商,我要賺差價1000");
// 返回cglib動態代理創造的實體類
Object obj = methodProxy.invokeSuper(o, objects);
System.out.println("收您2000");
return obj;
}
}
public class test {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(Market.class);
enhancer.setCallback(new CglibZhongJianShang());
Market market = (Market) enhancer.create();
market.sellProduct("手機");
// rap()可以被調用,沒有被增強
}
}
- cglib動態代理的特點:
cglib動態代理本質上是創建了被代理對象類的子類來實現動態代理,所以無法代理內部類(因爲內部類的創建依賴於外部類),cglib不能代理final修飾的方法,但是方法可以被正常調用(final修飾的方法不能被繼承)。
兩者的區別
-
java動態代理實現了被代理對象的接口,利用反射機制生成代理接口的匿名類,cglib是創建了被代理對象的子類來實現動態代理。
-
java動態代理是直接寫字節碼,cglib使用asm框架寫字節碼。
-
cglib的性能比jdk動態代理好,但是cglib創建動態代理所話費的事件比較長,因此無需頻繁創建代理對象的如線程池、單例用cglib比較好。
-
cglib動態代理無法代理內部類,因爲內部類的創建依賴外部類。如果非要代理內部類,有兩種方法:
- 內部類加static,static修飾的內部類可以作爲普通類來使用,不需要實例化外部類
- 在cglib創建類對象時傳入外部類(對象聲明類型是內部類)
-
動態代理應用場景
1、aop(Spring aop本質上就是通過動態代理實現的)
2、自定義第三方類庫中的某些方法
參考博客:https://blog.csdn.net/flyfeifei66/article/details/81481222等,侵權即刪