【DP-動態代理】JDK&Cglib

 

需求:加強未知方法的代碼

簡單方案:繼承或者聚合

  1. 繼承,調用方法先後加加強邏輯java

  2. 聚合 - 靜態代理ide

    1. 持有被代理類對象 或者接口this

    2. 可經過嵌套實現代理的組合 和 裝飾器模式很像spa

高級方案

  • 代理全部的類,不僅是某一類的接口,靜態的聚合方式成員屬性是具體的
JDK 動態代理 
package club.interview.design_pattern.chapt6_proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * @author QuCheng on 2020/6/15.
 */
public interface Vegetable {

    void growUp();

    class Cabbage implements Vegetable {

        @Override
        public void growUp() {
            System.out.println("捲心菜慢慢長大");
        }
    }

    class LogProxy implements InvocationHandler {

        Object o;

        public LogProxy(Object o) {
            this.o = o;
        }

        public static Object getProxy(Object object) {
            System.getProperties().setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
            return Proxy.newProxyInstance(object.getClass().getClassLoader(),
                    object.getClass().getInterfaces(), new LogProxy(object));
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("good goods study");
            Object invoke = method.invoke(o, args);
            System.out.println("day day up");
            return invoke;
        }

        public static void main(String[] args) {
            Vegetable v = (Vegetable) LogProxy.getProxy(new Cabbage());
            v.growUp();
        }
    }

} 
  • proxy源碼解讀
    • 實際產生的對象是$Proxy0.class的對象,繼承proxy,實現目標接口方法
    • 執行目標接口時實際調用super也就是proxy的InvokationHandler的invoke對象
  • 生成代理源碼解讀Proxy.newInstance(...)
    • 跟進去會發現底層是利用asm動態生成二進制文件$Proxy0.class 
Cglib
package club.interview.design_pattern.chapt6_proxy;
​
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
​
import java.lang.reflect.Method;
​
/**
 * @author QuCheng on 2020/6/15.
 */
public class CabbageCglib {
​
    public void growUp() {
        System.out.println("捲心菜慢慢長大");
    }
​
    static class LogProxyCglib implements MethodInterceptor {
​
        @SuppressWarnings("unchecked")
        static <T> T getProxy(T o) {
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(o.getClass());
            enhancer.setCallback(new LogProxyCglib());
            return (T) enhancer.create();
        }
​
        @Override
        public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
            System.out.println("good good study");
            // invokeSuper not invoke
            Object invoke = methodProxy.invokeSuper(o, objects);
            System.out.println("day day up");
            return invoke;
        }
    }
​
    public static void main(String[] args) {
​
        CabbageCglib cabbageCglib = LogProxyCglib.getProxy(new CabbageCglib());
        cabbageCglib.growUp();
    }
}

 

兩種動態代理對比
  • jdk 代理

    • 優勢:jdk原生,可代理有接口實現的類code

    • 缺點:代理類必須實現接口對象

  • cglibblog

    • 優勢:繼承

      • 被代理類無需實現接口接口

      • 實現簡單,無需聚合

    • 缺點:由於是採用繼承,被代理類不能被final修飾

相關文章
相關標籤/搜索