Java的动态代理

代码纪元 后端 2025-02-27

Java的动态代理

Java的动态代理

以下是Java动态代理的逐步解释:

Java动态代理详解

1. 动态代理的核心组件
  • java.lang.reflect.Proxy:生成代理对象的工具类。
  • java.lang.reflect.InvocationHandler:代理对象的方法调用处理器接口。
2. 实现步骤

步骤1:自定义接口java

代码解读
复制代码
public interface UserService { void addUser(String username); void deleteUser(String username); }

步骤2:实现自定接口java

代码解读
复制代码
public class UserServiceImpl implements UserService { @Override public void addUser(String username) { System.out.println("添加用户: " + username); } @Override public void deleteUser(String username) { System.out.println("删除用户: " + username); } }

步骤3:实现InvocationHandlerjava

代码解读
复制代码
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class LoggingHandler implements InvocationHandler { private final Object target; // 被代理的对象 public LoggingHandler(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 方法执行前逻辑 System.out.println("调用方法前: " + method.getName()); // 执行目标方法 Object result = method.invoke(target, args); // 方法执行后逻辑 System.out.println("调用方法后: " + method.getName()); return result; } }

步骤4:生成代理对象java

代码解读
复制代码
import java.lang.reflect.Proxy; public class DynamicProxyDemo { public static void main(String[] args) { // 创建目标对象 UserService realService = new UserServiceImpl(); // 创建InvocationHandler实例 InvocationHandler handler = new LoggingHandler(realService); // 生成代理对象 UserService proxyService = (UserService) Proxy.newProxyInstance( UserService.class.getClassLoader(), // 类加载器 new Class[]{UserService.class}, // 代理的接口数组 handler // InvocationHandler实例 ); // 通过代理对象调用方法 proxyService.addUser("Alice"); proxyService.deleteUser("Bob"); } }
3. 输出结果makefile
代码解读
复制代码
调用方法前: addUser 添加用户: Alice 调用方法后: addUser 调用方法前: deleteUser 删除用户: Bob 调用方法后: deleteUser
4. 动态代理的底层原理
  • 代理类生成Proxy.newProxyInstance() 在运行时动态生成代理类字节码。
  • 代理类结构:生成的代理类继承 Proxy 并实现指定接口。
  • 方法调用流程
    1. 客户端调用代理对象方法(如 addUser())。
    2. 代理类将调用转发到 InvocationHandler.invoke()
    3. invoke() 方法执行前置逻辑 → 调用目标方法 → 执行后置逻辑。
5. 动态代理的限制与解决方案
限制说明解决方案
只能代理接口无法直接代理没有接口的类使用CGLIB库(如Spring AOP默认行为)
性能开销反射调用比直接调用慢约5-20倍对性能敏感场景使用AspectJ编译时织入
无法代理final方法final方法无法被重写避免代理final方法或使用CGLIB
6. 动态代理的典型应用场景
  • AOP实现:日志、事务、权限校验等横切关注点。
  • 远程方法调用(RPC):如Dubbo、gRPC的客户端代理。
  • 延迟加载:例如Hibernate的延迟初始化代理。
  • Mock测试:动态生成测试替身(Test Double)。
7. 动态代理与CGLIB对比
特性JDK动态代理CGLIB
代理方式基于接口基于类继承
性能较慢(反射调用)较快(方法调用无反射)
依赖无需第三方库需要引入CGLIB库
方法限制无法代理无接口的类无法代理final方法或类
8. 高级技巧

查看生成的代理类字节码java

代码解读
复制代码
// 在启动JVM时添加以下参数 System.setProperty("jdk.proxy.ProxyGenerator.saveGeneratedFiles", "true");

处理Object方法(如toString)java

代码解读
复制代码
@Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (method.getDeclaringClass() == Object.class) { // 直接调用Object方法,不进行代理增强 return method.invoke(target, args); } // 其他方法的代理逻辑 // ... }

动态代理实现RPC框架伪代码java

代码解读
复制代码
public class RpcProxy implements InvocationHandler { private final String host; private final int port; public RpcProxy(String host, int port) { this.host = host; this.port = port; } @Override public Object invoke(Object proxy, Method method, Object[] args) { // 1. 序列化请求参数 byte[] requestData = serialize(method, args); // 2. 发送网络请求 byte[] responseData = sendRequest(host, port, requestData); // 3. 反序列化响应结果 return deserialize(responseData, method.getReturnType()); } }
9. 总结
  • 核心机制:通过反射动态生成代理类,拦截方法调用。
  • 适用场景:需要无侵入式增强方法功能的场合。
  • 性能权衡:灵活性与性能之间的取舍,需根据场景选择方案。
  • 扩展应用:结合其他技术(如注解、反射工厂)可实现更复杂的功能增强。

转载来源:https://juejin.cn/post/7474922326419275791

Apipost 私有化火热进行中

评论