Java動態代理

代理模式是設計模式的一種。動態代理的特點就是編譯階段不生成代理類,運行時生成代理類。常見的動態代理有兩種,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動態代理無法代理內部類,因爲內部類的創建依賴外部類。如果非要代理內部類,有兩種方法:

  1. 內部類加static,static修飾的內部類可以作爲普通類來使用,不需要實例化外部類
  2. 在cglib創建類對象時傳入外部類(對象聲明類型是內部類)
  • 動態代理應用場景

    1、aop(Spring aop本質上就是通過動態代理實現的)

    2、自定義第三方類庫中的某些方法

參考博客:https://blog.csdn.net/flyfeifei66/article/details/81481222等,侵權即刪

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章