【DP-动态代理】JDK&Cglib

 

需求:增强未知方法的代码

简单方案:继承或者聚合

  1. 继承,调用方法前后加增强逻辑

  2. 聚合 - 静态代理

    1. 持有被代理类对象 或者接口

    2. 可通过嵌套实现代理的组合 和 装饰器模式很像

高级方案

  • 代理所有的类,不只是某一类的接口,静态的聚合方式成员属性是具体的
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原生,可代理有接口实现的类

    • 缺点:代理类必须实现接口

  • cglib

    • 优点:

      • 被代理类无需实现接口

      • 实现简单,无需聚合

    • 缺点:因为是采用继承,被代理类不能被final修饰

原文地址:https://www.cnblogs.com/nightOfStreet/p/13141326.html