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

jdk动态代理如何实现

口语化答案

好的,面试官。jdk 的动态代理主要是依赖Proxy类InvocationHandler 接口。jdk 动态代理要求类必须有接口。在进行实现的时候,首先要定义接口,比如MyService,这个接口就是我们的正常功能的实现。但是希望在不更改MyService 的情况下增加额外功能,那么我们需要定义一个实现InvocationHandler 接口的实现类,同时在方法实现上面增加额外的逻辑。最后通过 Proxy 的 newProxyInstance 将二者结合到一起。就实现了动态代理。

题目解析

大家不要觉得动态代理很难理解,按照这个步骤其实你发现很简单。记忆的过程和 cglib 对比着看,就很轻松,面试也是属于常考一点的题目。

面试得分点

InvocationHandler 增强,Proxy 创建代理

题目详细答案

JDK 动态代理主要依赖于java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口来实现。

实现步骤

定义接口:定义需要代理的接口。

实现接口:创建接口的实现类。

创建调用处理器:实现InvocationHandler接口,并在invoke方法中定义代理逻辑。

创建代理对象:通过Proxy.newProxyInstance方法创建代理对象。

代码 Demo

假设我们有一个简单的服务接口MyService和它的实现类MyServiceImpl,我们将通过 JDK 动态代理为MyService创建一个代理对象,并在方法调用前后添加日志。

1. 定义接口
public interface MyService {void performTask();
}
2. 实现接口
public class MyServiceImpl implements MyService {@Overridepublic void performTask() {System.out.println("Performing task");}
}
3. 创建调用处理器
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;public class LoggingInvocationHandler implements InvocationHandler {private final Object target;public LoggingInvocationHandler(Object target) {this.target = target;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("Logging before method execution: " + method.getName());Object result = method.invoke(target, args);System.out.println("Logging after method execution: " + method.getName());return result;}
}
4. 创建代理对象并使用
import java.lang.reflect.Proxy;public class MainApp {public static void main(String[] args) {// 创建目标对象MyService myService = new MyServiceImpl();// 创建调用处理器LoggingInvocationHandler handler = new LoggingInvocationHandler(myService);// 创建代理对象MyService proxyInstance = (MyService) Proxy.newProxyInstance(myService.getClass().getClassLoader(),myService.getClass().getInterfaces(),handler);// 调用代理对象的方法proxyInstance.performTask();}
}

详细解释

1、 接口定义和实现

MyService是一个简单的接口,定义了一个方法performTask。

MyServiceImpl是MyService的实现类,实现了performTask方法。

2、 调用处理器

LoggingInvocationHandler实现了InvocationHandler接口。它的invoke方法在代理对象的方法调用时被调用。invoke方法接收三个参数:proxy:代理对象。method:被调用的方法。args:方法参数。在invoke方法中,我们在方法调用前后添加了日志打印。

3、 创建代理对象

使用Proxy.newProxyInstance方法创建代理对象。

newProxyInstance方法接收三个参数:类加载器:通常使用目标对象的类加载器。接口数组:目标对象实现的所有接口。调用处理器:实现了InvocationHandler接口的实例。

4、 使用代理对象

通过代理对象调用方法时,实际调用的是LoggingInvocationHandler的invoke方法。

在invoke方法中,首先打印日志,然后通过反射调用目标对象的方法,最后再打印日志。

JDK动态代理通俗详解

面试官您好,关于JDK动态代理,我用一个生活中的例子来帮助理解:

快递代收点类比

想象你网购了一件商品:

  1. 商家(MyServiceImpl):实际发货的人
  2. 快递代收点(Proxy):中间代理点
  3. 代收点规则(InvocationHandler):代收点提供的额外服务(比如验货、暂存)

实现步骤详解

1. 定义服务接口(购物清单)

// 就像网购时商家承诺的服务标准
public interface ShoppingService {void deliverItem();  // 送货服务String checkQuality(); // 验货服务
}

2. 实际商家实现(真实发货)

public class Amazon implements ShoppingService {@Overridepublic void deliverItem() {System.out.println("亚马逊发货中...");}@Overridepublic String checkQuality() {return "正品保障";}
}

3. 创建代收点规则(增值服务)

public class ProxyService implements InvocationHandler {private Object target;  // 真实的商家对象public ProxyService(Object target) {this.target = target;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 前置增强:代收点验货if(method.getName().equals("deliverItem")) {System.out.println("【代收点】快递消毒中...");}// 执行原方法(让商家正常发货)Object result = method.invoke(target, args);// 后置增强:签收服务if(method.getName().equals("deliverItem")) {System.out.println("【代收点】已签收,短信通知客户");}return result;}
}

4. 创建代收点(生成代理)

public class Client {public static void main(String[] args) {// 真实商家ShoppingService amazon = new Amazon();// 创建代理规则InvocationHandler handler = new ProxyService(amazon);// 建立代收点(生成代理实例)ShoppingService proxy = (ShoppingService) Proxy.newProxyInstance(amazon.getClass().getClassLoader(),amazon.getClass().getInterfaces(),handler);// 客户通过代收点购物proxy.deliverItem();System.out.println("验货结果:" + proxy.checkQuality());}
}

输出结果

【代收点】快递消毒中...
亚马逊发货中...
【代收点】已签收,短信通知客户
验货结果:正品保障

关键点说明

  1. 必须要有接口:就像必须通过电商平台下单,不能直接找路边摊
  2. InvocationHandler是核心:所有增强逻辑都在这里实现
  3. Proxy.newProxyInstance三要素
    • 类加载器:用原来的就行
    • 接口数组:说明要代理哪些服务
    • 处理规则:怎么增强这些服务

实际项目应用

在我们电商系统中:

  1. 支付服务接口用JDK代理添加日志
  2. 订单服务接口用JDK代理添加事务
  3. 商品服务接口用JDK代理做缓存

与CGLIB对比记忆

特性

JDK动态代理

CGLIB

依赖

必须实现接口

不需要接口

原理

实现相同接口

继承目标类

性能

反射调用稍慢

直接调用更快

适用场景

Spring默认对接口的代理

代理普通类

这样设计既保持了规范性(面向接口编程),又能灵活添加通用功能。

http://www.dtcms.com/a/318055.html

相关文章:

  • 【补题】Codeforces Round 779 (Div. 2) C. Shinju and the Lost Permutation
  • 【补题】CodeTON Round 1 (Div. 1 + Div. 2, Rated, Prizes!) D. K-good
  • 大数据之HBase
  • 深度学习-卷积神经网络CNN-多输入输出通道
  • MySQL数据库索引及底层数据结构
  • 宝塔部署go 项目
  • Maven--打包方式详解 (pom、war、jar)
  • 各类排序算法
  • FastAPI(未结束)
  • 【React 插件】@uiw/react-md-editor 使用教程:从基础使用到自定义扩展
  • STM32串口通信指南
  • 基于RPR模型的机械臂手写器simulink建模与仿真
  • easyExcel 读取有合并单元格数据
  • 对接钉钉审批过程记录(C#版本)
  • 高可用改造之构建​​双活冗余的TDengine时序数据处理架构
  • 通过最严时序标准,再登产业图谱榜首,TDengine 时序数据库在可信数据库大会荣获双荣誉
  • AI 软件工程开发 AI 算法 架构与业务
  • Effective C++ 条款25:考虑写出一个不抛异常的swap函数
  • linux 使用docker时开放的端口不受防火墙控制的解决方案
  • 医疗AI中GPU部署的“非对等全节点架构“方案分析(上)
  • AI领域的三箭齐发之夜 - genie3,gpt-oss, Opus 4.1
  • hyper-v常见问题解答(此文会持续更新)
  • DNS 服务器
  • 远程连接----ubuntu ,rocky 等Linux系统,WindTerm_2.7.0
  • 当前主流GPU全景讲解:架构、功能与应用方向
  • 一种简单的3dnr去噪算法介绍
  • 北京-4年功能测试2年空窗-报培训班学测开-第六十九天-投简历第一天-从兴奋到害怕
  • Unity工具—Inspector面板增加Rect Transform组件上下左右移动的工具
  • linux IO介绍
  • Android系统性能分析利器:深入解析Tracing框架