Skip to content

动态代理

概念

动态代理是一种在运行时动态生成代理对象的技术。
通过使用动态代理,可以在不修改原始类的情况下,对其方法进行增强或拦截,以实现一些额外的功能。

在 Java 中,动态代理是通过反射机制实现的。
Java 提供了两种方式来创建动态代理:基于接口的代理和基于类的代理。

  1. 基于接口的代理:使用 Java 提供的 java.lang.reflect.Proxy 类来创建代理对象。该类提供了一个静态方法 newProxyInstance,通过传入目标接口、类加载器和调用处理器来创建代理对象。代理对象实现了目标接口,并在方法调用时委托给调用处理器进行处理。

  2. 基于类的代理:使用第三方库(如 CGLIB)来生成代理对象。CGLIB 通过生成目标类的子类来实现代理,覆盖了父类的方法,并在方法调用时插入额外的逻辑。

动态代理常用于 AOP(面向切面编程)和框架开发中,例如在事务管理、日志记录和性能监控等方面。通过代理,可以在方法的执行前后插入自定义的逻辑,而不需要修改原始类的代码。

动态代理撑起了java各种架构的半壁江山。

接口动态代理

接口动态代理,我在插件机制中设计了一套Demo。
具体代码见gitee:
https://gitee.com/fly2world_admin/plugin-demo-proxy.git

接口代理经典案例: Mybatis

具体思路如下:

  1. 创建接口
java
package top.mybatisx.plugin_proxy.plugin;

/**
 * 考勤插件接口
 */
public interface ClockInPlugin {

    // 安装
    void install();

}
  1. 创建处理器,实现 InvocationHandler 接口,实现 invoke 代理函数
java
/**
 * 考勤业务
 */
public class ClockInService implements InvocationHandler {

    private ClockType clockType;

    /**
     * 考勤执行
     */
    public ClockInService(ClockType clockType) {
        this.clockType = clockType;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("-----------可定义拦截器---------");
        if (args != null) {
            for (Object arg : args) {
                System.out.println("通过代理拿到了参数:" + arg);
            }
        }
        // 初始化插件
        ClockInPlugin clockInPlugin = switch (clockType) {
            case sytem -> new ClockInPluginImpl();
            case dingding -> new DingDingClockInPluginImpl();
            case weixin -> new WeixinClockInPluginImpl();
        };
        return method.invoke(clockInPlugin, args);
    }

}
  1. 利用 Proxy.newProxyInstance 构造代理对象
  2. 直接使用接口对象
java
public static void main(String[] args) {
        // 调用考勤
        ClockType clockType = ClockType.dingding;

        // 构造动态代理
        ClockInPlugin clockInPlugin = (ClockInPlugin) Proxy.newProxyInstance(ClockInPlugin.class.getClassLoader(), new Class[]{ClockInPlugin.class}, new ClockInService(clockType));

        // 调用纯接口,更加纯粹
        clockInPlugin.install();
        clockInPlugin.turnData();
        clockInPlugin.importData();
        clockInPlugin.destory();
    }

基于类的代理

  1. 使用第三方库(如 CGLIB)来生成代理对象。
  2. 使用Spring版的 CGLIB 生成代理。

注:使用cglib不支持 graalvm 生成可执行文件。