动态代理

简介

动态代理在java中有着广泛的应用。比如Spring AOP、Hibernate数据查询、测试框架的后端mock、RPC远程调用、Java注解对象获取、日志、用户鉴权、全局性异常处理、性能监控,甚至事务处理等。

静态代理

假如有1个接口,如下:

public interface OrderService {
    void create(int id);
    void pay(int id);
}

实现为:

public class OrderServiceImpl implements OrderService {

    @Override
    public void create(int id) {
        System.out.println("create order");
    }

    @Override
    public void pay(int id) {
        System.out.println("pay order");
    }
}

使用静态代理对其增强

import java.util.Date;

/**
 * 静态代理
 *
 * @author dcx
 * @since 2023-06-21 10:04
 **/
public class OrderServiceProxy implements OrderService {

    //被代理的对象
    private OrderService orderService;

    public OrderServiceProxy(OrderService orderService) {
        this.orderService = orderService;
    }

    @Override
    public void create(int id) {
        before();
        orderService.create(id);
        after();
    }

    @Override
    public void pay(int id) {
        before();
        orderService.pay(id);
        after();
    }

    private void before() {
        System.out.println("before: " + new Date());
    }

    private void after() {
        System.out.println("after: " + new Date());
    }
}

使用

 public static void staticProxy() {
        //生成被代理对象
        OrderService orderService = new OrderServiceImpl();
        //生成代理对象
        OrderServiceProxy orderServiceProxy = new OrderServiceProxy(orderService);
        //代理对象执行
        orderServiceProxy.create(1);
        orderServiceProxy.pay(1);
    }

优点

这样就在不侵入原先代码的情况下,对原有对象进行了增强。

不足

  1. 新增,删除方法时,需要同时修改目标类和代理类。

  2. 当代理多个类的时候,造成代码混乱。

思考

代理类是根据目标类产生,有一定的规律。有没有什么办法在类加载阶段完成代理类的自动生成呢?

介绍2种现成的实现:

  1. 通过实现接口生成代理类。-->JDK动态代理。

  2. 通过继承生成代理类-->CGLib。

JDK动态代理

通过实现 InvocationHandler,生成代理处理器。


import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Date;

/**
 * jdk 动态代理,实现日志打印
 *
 * @author dcx
 * @since 2023-06-21 10:12
 **/
public class LogHandler implements InvocationHandler {

    //被代理的对象
    Object target;

    public LogHandler(Object target) {
        this.target = target;
    }

    /**
     * 反射对象
     * @param proxy 代理对象
     * @param method    代理的方法
     * @param args  方法入参
     * @return java.lang.Object  方法执行结果
     * @author dcx
     * @date 2023/6/21 10:15
     **/
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        before();
        Object result = method.invoke(target, args);
        after();
        return result;
    }

    private void before() {
        System.out.println("before: " + new Date());
    }

    private void after() {
        System.out.println("after: " + new Date());
    }
}

使用

public static void jdkProxy(){
    //目标类
    OrderService orderService = new OrderServiceImpl();
    //获取类加载器
    ClassLoader classLoader = orderService.getClass().getClassLoader();
    //获取对象实现的接口类,OrderServiceImpl实现的是OrderService接口类
    Class<?>[] interfaces = orderService.getClass().getInterfaces();
    //创建代理处理器
    LogHandler logHandler = new LogHandler(orderService);
    //创建代理对象
    OrderService orderServiceProxy = (OrderService) Proxy.newProxyInstance(classLoader, interfaces, logHandler);
    //代理对象执行方法
    orderServiceProxy.create(1);
    orderServiceProxy.pay(1);
    //输出代理对象class文件
    ProxyUtils.generateClassFile(orderService.getClass(),"OrderServiceImpljdkProxy");
}

查看下生成的代理类


import com.skuu.proxy.OrderService;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class OrderServiceImpljdkProxy extends Proxy implements OrderService {
    private static Method m1;
    private static Method m4;
    private static Method m2;
    private static Method m3;
    private static Method m0;

    public OrderServiceImpljdkProxy(InvocationHandler var1) throws  {
        super(var1);
    }

    public final boolean equals(Object var1) throws  {
        try {
            return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final void create(int var1) throws  {
        try {
            super.h.invoke(this, m4, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final String toString() throws  {
        try {
            return (String)super.h.invoke(this, m2, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final void pay(int var1) throws  {
        try {
            super.h.invoke(this, m3, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final int hashCode() throws  {
        try {
            return (Integer)super.h.invoke(this, m0, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m4 = Class.forName("com.skuu.proxy.OrderService").getMethod("create", Integer.TYPE);
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m3 = Class.forName("com.skuu.proxy.OrderService").getMethod("pay", Integer.TYPE);
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}
  1. 代理类继承了 Proxy 类,并且实现了被代理的所有接口,以及equals、hashCode、toString等方法。

  2. 类和所有方法都被 public final 修饰,所以代理类只可被使用,不可以再被继承。

  3. 目标类的每个方法,在代理类中通过反射生成Method对象。

  4. 每个方法中的super.h都是之前设置的代理控制器(LogHandler),来执行真正的逻辑。

代理对象UML

可以看出,代理对象执行方法时,会通过继承于父类的InvocationHandler来调用代理控制器,最终调用目标类的方法。

CGLIB动态代理

目标类

public class Order {
    public void create(int id) {
        System.out.println("create");
    }

    public void pay(int id) {
        System.out.println("pay");
    }
}

日志拦截器


import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;
import java.util.Date;

/**
 * cglib动态代理处理
 *
 * @author dcx
 * @since 2023-06-21 10:59
 **/
public class LogInterceptor implements MethodInterceptor {

    /**
     * 对象执行拦截
     *
     * @param o           被代理的对象
     * @param method      拦截的方法
     * @param objects     参数列表
     * @param methodProxy 对方法的代理
     * @return java.lang.Object
     * @author dcx
     * @date 2023/6/21 11:00
     **/
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        before();
        // 注意这里是调用 invokeSuper 而不是 invoke,否则死循环,methodProxy.invokesuper执行的是原始类的方法,method.invoke执行的是子类的方法
        Object result = methodProxy.invokeSuper(o, objects);
        after();
        return result;
    }

    private void before() {
        System.out.println("before: " + new Date());
    }

    private void after() {
        System.out.println("after: " + new Date());
    }
}

使用

public static void cglibProxy(){
    //生成拦截处理器
    LogInterceptor logInterceptor = new LogInterceptor();
    //方法增强处理类
    Enhancer enhancer = new Enhancer();
    //设置超类
    enhancer.setSuperclass(Order.class);
    //设置回调时拦截增强
    enhancer.setCallback(logInterceptor);
    //创建增强类
    Order order = (Order) enhancer.create();
    order.create(1);
    order.pay(1);
}
  1. 查找目标类上的所有非final 的public类型的方法定义;

  2. 将这些方法的定义转换成字节码;

  3. 将组成的字节码转换成相应的代理的class对象;

  4. 实现 MethodInterceptor接口,用来处理对代理类上所有方法的请求。

JDK动态代理与CGLIB动态代理对比

JDK动态代理:基于Java反射机制实现,必须要实现了接口的业务类才能用这种办法生成代理对象。

cglib动态代理:基于ASM机制实现,通过生成业务类的子类作为代理类。

推荐使用:如spring一般,如果目标类实现了接口,就用jdk动态代理,反之则用cglib。

Last updated

Was this helpful?