当前位置: 首页 > 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.lryc.cn/news/612189.html

相关文章:

  • 力扣经典算法篇-45-回文数(数字处理:求余+整除,字符串处理:左右指针)
  • Unity笔记(二)——Time、Vector3、位置位移、角度、旋转、缩放、看向
  • 【历史人物】【范仲淹】简历与生平
  • 看不见的伪造痕迹:AI时代的鉴伪攻防战
  • NAT转化
  • 後端開發技術教學(二) 條件指令、循環結構、定義函數
  • 在 Visual Studio Code 中免费使用 Gemini 2.5 Pro API
  • 力扣面试150(48/150)
  • cacti
  • qt6 cmake vscode加载qrc图片资源
  • Milvus 向量数据库内存使用相关了解
  • 《第十篇》深入解析 `MilvusKBService`:基于 Milvus 的知识库服务实现
  • Vscode 解决 git插件Failed to connect to github.com port 443 connection timed out
  • FastAPI(未结束)
  • 实名认证 —— 腾讯云驾驶证识别接口
  • Spring_事务
  • docker相关操作记录
  • C语言控制语句练习题1
  • 记一次ORACLE ORA-00600 [19004] 错误的分析与解决方法
  • ABAP QRFC 队列函数的使用
  • 院校机试刷题第二十一天|回顾代码随想录第十六天、
  • gorm:初识gorm
  • 线性代数中矩阵的基本运算运算
  • 二、Istio流量治理(一)
  • Kali Linux虚拟机安装和中文配置详细教程(2025版)
  • Aop中的相关术语
  • FluentUI的介绍与使用案列
  • K8S的POD数量限制
  • 《Transformer黑魔法Mask与Softmax、Attention的关系:一个-∞符号如何让AI学会“选择性失明“》
  • sqli-labs靶场less40-less45