当前位置: 首页 > article >正文

Java 代理模式深度解析:从静态到动态的实现与原理

目录

一、引言

二、静态代理:手动实现的基础形式

1. 定义业务接口与实现类

2. 创建代理类

3. 组合使用代理类

4. 优缺点分析

三、JDK 动态代理:基于接口的运行时代理

1. 核心实现

定义 InvocationHandler

客户端调用

2. 核心原理

代理类结构分析

模拟 JDK 动态代理实现

3. 优缺点

四、CGLIB 动态代理:基于继承的字节码增强

1. 核心实现

定义 MethodInterceptor

客户端调用

2. 核心原理

字节码增强流程

关键类解析

模拟 CGLIB 动态代理实现

3. 优缺点

五、代理模式对比与选择

六、Java动态代理的各种实现方式

一、引言

在 Java 开发中,代理模式(Proxy Pattern)是一种常用的设计模式。它通过引入中间层(代理类)来控制对目标对象的访问,允许在不修改原始代码的前提下添加额外功能。当我们遇到以下场景时,代理模式往往能发挥关键作用:

  • 在业务方法前后添加日志、监控等通用逻辑
  • 实现业务代码与通用功能的解耦
  • 处理仅有接口而无具体实现的场景(如 MyBatis Mapper)
  • 理解框架底层动态代理实现(如 Spring AOP)

本文将通过具体案例,深入探讨 Java 代理模式的实现方式与核心原理,并结合代码进行详细解析。

二、静态代理:手动实现的基础形式

静态代理通过手动编写代理类实现功能增强,是代理模式的基础形式。以下是其核心实现步骤:

1. 定义业务接口与实现类

// MyService接口
public interface MyService {
    void doTask();
}

// MyServiceImpl实现类
public class MyServiceImpl implements MyService {
    @Override
    public void doTask() {
        System.out.println("Task doing");
        try { Thread.sleep(10); } catch (InterruptedException e) { /* ... */ }
        System.out.println("Task done");
    }
}

2. 创建代理类

// 日志代理类
public class MyServiceLogProxy implements MyService {
    private final MyService target;
    public MyServiceLogProxy(MyService target) { this.target = target; }
    @Override public void doTask() {
        System.out.println("----do task log start----");
        target.doTask();
        System.out.println("----do task log end---");
    }
}

// 监控代理类
public class MyServiceMonitorProxy implements MyService {
    private final MyService target;
    public MyServiceMonitorProxy(MyService target) { this.target = target; }
    @Override public void doTask() {
        long start = System.currentTimeMillis();
        target.doTask();
        System.out.printf("Cost: %d ms%n", System.currentTimeMillis() - start);
    }
}

3. 组合使用代理类

// 客户端代码
public class MyServiceClient {
    public static void main(String[] args) {
        MyService service = new MyServiceImpl();
        MyService proxied = new MyServiceLogProxy(
            new MyServiceMonitorProxy(service)
        );
        proxied.doTask();
    }
}

4. 优缺点分析

  • 优点:实现简单,易于理解
  • 缺点
    • 代理类与接口强绑定,无法复用
    • 无法处理无接口的场景

三、JDK 动态代理:基于接口的运行时代理

JDK 动态代理通过反射机制在运行时生成代理类,是 Spring AOP 的默认实现方式。

1. 核心实现

定义 InvocationHandler
// 日志处理器
public class JDKDynamicLogProxy implements InvocationHandler {

    private Object target;

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

    /**
     * 获取被代理接口实例对象
     * @param 
     * @return
     */
    public <T> T getProxy() {
        return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("----do task log start----");
        Object result = method.invoke(target, args);
        System.out.println("----do task log end---");
        return result;
    }
}
//JDK动态代理-监控
public class JDKDynamicMonitorProxy implements InvocationHandler {

    private Object target;

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

    /**
     * 获取被代理接口实例对象
     * @param 
     * @return
     */
    public <T> T getProxy() {
        /*
        Proxy.newProxyInstance()方法接受三个参数:
        ClassLoader loader:指定当前目标对象使用的类加载器,获取加载器的方法是固定的
        Class[] interfaces:指定目标对象实现的接口的类型,使用泛型方式确认类型
        InvocationHandler:指定动态处理器,执行目标对象的方法时,会触发事件处理器的方法
         */
        return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        long start = System.currentTimeMillis();
        System.out.println("do task start time:" + start);

        // 调用业务方法
        Object result = method.invoke(target, args);

        long end = System.currentTimeMillis();
        System.out.println("do task end time:" + end);

        System.out.println("do task cost " + (end - start) + "ms");

        return result;
    }
}
客户端调用
// JDKDynamicClient
public class JDKDynamicClient {
    public static void main(String[] args) {
        System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
        MyService service = new MyServiceImpl();
        MyService proxied = new JDKDynamicLogProxy(service).getProxy();
        proxied.doTask();
    }
}

2. 核心原理

JDK 动态代理的核心在于java.lang.reflect.Proxyjava.lang.reflect.InvocationHandler的配合。当调用代理对象的方法时,实际执行的是InvocationHandlerinvoke方法。其核心流程如下:

  1. 字节码生成:通过Proxy.newProxyInstance生成动态代理类字节码,该类会实现目标接口。
  2. 方法拦截:代理类的所有方法调用都会委派给InvocationHandlerinvoke方法。
  3. 反射调用:在invoke方法中,通过反射调用目标对象的真实方法。
代理类结构分析

生成的代理类(如$Proxy0)会实现目标接口,并持有InvocationHandler实例:

public final class $Proxy0 implements MyService {
    private final InvocationHandler h;
    
    public $Proxy0(InvocationHandler h) { this.h = h; }
    
    public void doTask() {
        h.invoke(this, MyService.class.getMethod("doTask"), null);
    }
}
模拟 JDK 动态代理实现
代理逻辑的入口
public interface InvocationHandler {

    void invoke(Object o, Method m);

}
public class MonitorHandler implements InvocationHandler {

    private Object target;

    public MonitorHandler(Object target) {
        super();
        this.target = target;
    }

    @Override
    public void invoke(Object o, Method m) {
        long start = System.currentTimeMillis();

        System.out.println("do task start time:" + start);

        try {
            m.invoke(target);
        } catch (Exception e) {
            e.printStackTrace();
        }

        long end = System.currentTimeMillis();
        System.out.println("do task end time:" + end);
        System.out.println("do task cost " + (end - start) + "ms");
    }
}
模拟JDK动态代理类
public class Proxy {

    public static Object newProxyInstance(Class infce, InvocationHandler h) throws Exception {
        String methodStr = "";

        Method[] methods = infce.getMethods();

        for (Method m : methods) {
            methodStr += "    @Override\n" +
                    "    public void " + m.getName() + "() {\n" +
                    "        try {\n" +
                    "            Method md = " + infce.getName() + ".class.getMethod(\"" + m.getName() + "\");\n" +
                    "            h.invoke(this, md);\n" +
                    "        } catch(Exception e) {\n" +
                    "            e.printStackTrace();\n" +
                    "        }\n" +
                    "    }\n";
        }

        String sourceCode = "package cn.dmlove.proxy;\n" +
                "\n" +
                "import java.lang.reflect.Method;\n" +
                "import cn.dmlove.demo3.InvocationHandler;\n" +
                "\n" +
                "public class $JDKDynamicProxy1 implements " + infce.getName() + "{\n" +
                "\n" +
                "    private InvocationHandler h;\n" +
                "\n" +
                "    public $JDKDynamicProxy1(InvocationHandler h) {\n" +
                "        this.h = h;\n" +
                "    }\n" +
                "\n" +
                methodStr +
                "}";

        // 生成java源码文件
        String javaFileName = System.getProperty("user.dir") + "/src/main/java/cn/dmlove/proxy/$JDKDynamicProxy1.java";
        File javaFile = new File(javaFileName);
        FileWriter fileWriter = new FileWriter(javaFile);
        fileWriter.write(sourceCode);
        fileWriter.flush();
        fileWriter.close();

        // 获取编译器
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();

        // 获取java文件管理器
        StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
        // 要编译的java文件
        Iterable javaFileObjects = fileManager.getJavaFileObjects(javaFile);

        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        // 指定class文件目录
        String flag = "-d";
        String outDir = "";
        try {
            File classPath = new File(classLoader.getResource("").toURI());
            outDir = classPath.getAbsolutePath() + File.separator;
        } catch (URISyntaxException e1) {
            e1.printStackTrace();
        }
        Iterable options = Arrays.asList(flag, outDir);
        // 获取编译任务
        JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, null, options, null, javaFileObjects);
        // 执行编译任务
        task.call();

        // 关闭java文件管理器
        fileManager.close();

        // class文件load到内存
        Class clazz = classLoader.loadClass("cn.dmlove.proxy.$JDKDynamicProxy1");

        Constructor cons = clazz.getConstructor(InvocationHandler.class);

        return cons.newInstance(h);
    }

}
public class $JDKDynamicProxy1 implements cn.dmlove.MyService {

    private InvocationHandler h;

    public $JDKDynamicProxy1(InvocationHandler h) {
        this.h = h;
    }

    @Override
    public void doTask() {
        try {
            Method md = cn.dmlove.MyService.class.getMethod("doTask");
            h.invoke(this, md);
        } catch(Exception e) {
            e.printStackTrace();
        }
    }
}
模拟JDK动态代理调用
public class Client {

    public static void main(String[] args) throws Exception {
        MyService myService = new MyServiceImpl();
        InvocationHandler h = new MonitorHandler(myService);

        MyService m = (MyService)Proxy.newProxyInstance(MyService.class, h);

        m.doTask();
    }
}

运行结果:

生成代理类

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package com.sun.proxy;

import cn.dmlove.MyService;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class $Proxy0 extends Proxy implements MyService {
    private static Method m1;
    private static Method m2;
    private static Method m3;
    private static Method m0;

    public $Proxy0(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 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 doTask() throws  {
        try {
            super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    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"));
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m3 = Class.forName("cn.dmlove.MyService").getMethod("doTask");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}

3. 优缺点

  • 优点
    • 完全运行时生成,无需手动编码
    • 支持接口方法拦截
  • 缺点
    • 仅支持接口代理
    • 反射调用存在性能损耗

四、CGLIB 动态代理:基于继承的字节码增强

CGLIB 通过字节码生成技术为类创建子类,实现对非接口类的代理。

1. 核心实现

定义 MethodInterceptor
/**
 * cglib动态监控代理
 */
public class CglibMonitorProxy implements MethodInterceptor {

    private Object target;

    public final Object getInstance(final Object target) {
        this.target = target;
        //cglib 中字节码加强器,用来创建动态代理
        Enhancer enhancer = new Enhancer();
        // 设置要创建动态代理的类
        enhancer.setSuperclass(this.target.getClass());
        // 设置回调,这里相当于是对于代理类上所有方法的调用,都会调用CallBack,而Callback则需要实现intercept()方法进行拦截
        enhancer.setCallback(this);
        // 返回实例
        return enhancer.create();
    }

    @Override
    public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        long start = System.currentTimeMillis();
        System.out.println("do task start time:" + start);

        Object result = methodProxy.invokeSuper(object, args);

        long end = System.currentTimeMillis();
        System.out.println("do task end time:" + end);
        System.out.println("do task cost " + (end - start) + "ms");

        return result;
    }
客户端调用
public class CglibProxyClient {

    public static void main(String[] args) {
        //获取代理
        MyServiceImpl myServiceImplProxy = (MyServiceImpl) new CglibMonitorProxy().getInstance(new MyServiceImpl());

        // 执行
        myServiceImplProxy.doTask();
    }
}

2. 核心原理

字节码增强流程
  1. 子类生成:CGLIB 通过Enhancer生成目标类的子类
  2. 方法拦截:重写父类方法,通过MethodInterceptor实现逻辑增强
  3. 快速调用:使用MethodProxy优化方法调用,避免反射开销(文档 3-59)
关键类解析
  • Enhancer:字节码增强器,用于设置父类和回调
  • MethodInterceptor:定义拦截逻辑,类似 JDK 的InvocationHandler
  • MethodProxy:缓存方法调用,提升性能
模拟 CGLIB 动态代理实现
import java.lang.reflect.Method;

// 目标类
class TargetClass {
    public void doSomething() {
        System.out.println("Target is doing something.");
    }
}

// 方法拦截器接口
interface MethodInterceptor {
    Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable;
}

// 方法代理类
class MethodProxy {
    private Method method;

    public MethodProxy(Method method) {
        this.method = method;
    }

    public Object invokeSuper(Object obj, Object[] args) throws Throwable {
        return method.invoke(obj, args);
    }
}

// 模拟 Enhancer 类,用于生成代理类
class Enhancer {
    private Class<?> superclass;
    private MethodInterceptor callback;

    public void setSuperclass(Class<?> superclass) {
        this.superclass = superclass;
    }

    public void setCallback(MethodInterceptor callback) {
        this.callback = callback;
    }

    public Object create() {
        try {
            // 这里模拟生成代理类,实际上 CGLIB 会动态生成字节码
            // 这里简单使用反射创建目标类的实例
            TargetClass target = (TargetClass) superclass.getDeclaredConstructor().newInstance();
            return new ProxyClass(target, callback);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    // 模拟生成的代理类
    private static class ProxyClass extends TargetClass {
        private TargetClass target;
        private MethodInterceptor callback;

        public ProxyClass(TargetClass target, MethodInterceptor callback) {
            this.target = target;
            this.callback = callback;
        }

        @Override
        public void doSomething() {
            try {
                Method method = TargetClass.class.getMethod("doSomething");
                MethodProxy proxy = new MethodProxy(method);
                callback.intercept(this, method, new Object[0], proxy);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

// 测试代码
public class SimulateCglibProxy {
    public static void main(String[] args) {
        // 创建 Enhancer 实例
        Enhancer enhancer = new Enhancer();
        // 设置目标类
        enhancer.setSuperclass(TargetClass.class);
        // 设置方法拦截器
        enhancer.setCallback(new MethodInterceptor() {
            @Override
            public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
                System.out.println("Before method execution.");
                Object result = proxy.invokeSuper(obj, args);
                System.out.println("After method execution.");
                return result;
            }
        });
        // 创建代理对象
        TargetClass proxy = (TargetClass) enhancer.create();
        // 调用代理对象的方法
        proxy.doSomething();
    }
}    

3. 优缺点

  • 优点
    • 支持非接口类代理
    • 性能优于 JDK 代理
  • 缺点
    • 无法代理final类 / 方法
    • 大量使用可能导致 PermGen 内存溢出

五、代理模式对比与选择

特性静态代理JDK 动态代理CGLIB 动态代理
代理机制手动实现接口实现子类继承
生成时机编译期运行期运行期
性能中(反射调用)高(字节码优化)
灵活性
适用场景简单功能扩展接口类代理非接口类代理

六、Java动态代理的各种实现方式


http://www.kler.cn/a/600110.html

相关文章:

  • 【jvm】垃圾回收的并行和并发
  • 鸿蒙harmonyOS:笔记 正则表达式
  • JVM常用概念之编译器黑洞
  • 数学建模:MATLAB卷积神经网络
  • Langchain 自定义工具和内置工具
  • FRP结合Nginx实现HTTPS服务穿透
  • LVGL移植详细教程(基于STM32F407+rt-thread+FSMC接口屏+V9版本)
  • java 设置操作系统编码、jvm平台编码和日志文件编码都为UTF-8的操作方式
  • 现代化前端异常治理与容灾体系深度解析
  • 本周安全速报(2025.3.18~3.24)
  • VSCODE上ckg_server_linux进程占用CPU过多
  • C++红黑树的深入解析:从理论到实践
  • Mysql--日志(错误日志、二进制日志、查询日志、慢查询日志)
  • Wireshark网络抓包分析使用详解
  • SAP SD学习笔记34 - 预詑品(寄售物料)之 预詑品返品(KR),预詑品引取(KA)
  • 青少年编程与数学 02-011 MySQL数据库应用 16课题、安全机制
  • js 中 如何获取数组的交集【面试题】
  • 如何为AI开发选择合适的服务器?
  • 《HarmonyOS Next群头像拼接与组件截图技术解析》
  • 第六届IEEE人工智能、网络与信息技术国际学术会议(AINIT 2025)