哈喽,各位小伙伴们,你们好呀,我是喵手。运营社区:掘金/C站/腾讯云/阿里云/华为云/51CTO(全网同号);欢迎大家常来逛逛,互相学习。
今天我要给大家分享一些自己日常学习到的一些知识点,并以文字的形式跟大家一起交流,互相学习,一个人虽可以走的更快,但一群人可以走的更远。
我是一名后端开发爱好者,工作日常接触到最多的就是Java语言啦,所以我都尽量抽业余时间把自己所学到所会的,通过文章的形式进行输出,希望以这种方式帮助到更多的初学者或者想入门的小伙伴们,同时也能对自己的技术进行沉淀,加以复盘,查缺补漏。
小伙伴们在批阅的过程中,如果觉得文章不错,欢迎点赞、收藏、关注哦。三连即是对作者我写作道路上最好的鼓励与支持!
前言
众所周知,Java 反射(Reflection)是 Java 语言提供的一种强大的功能,它允许程序在运行时访问和操作类的信息。反射不仅支持访问类的字段、方法、构造器等,还能动态创建对象和调用方法。动态代理(Dynamic Proxy)是 Java 反射中的一个重要特性,它允许你在运行时创建代理对象,进而增强对象的功能。
本文将带着大家深入探讨 Java 动态代理的工作原理、如何创建动态代理对象以及如何使用它来增强现有的功能,又是干货满满的一期,大家可千万别走神,我只讲这一遍。
1. 动态代理
概述
所谓Java 动态代理,它允许我们在运行时创建一个代理对象,该对象实现指定的接口,并将方法调用转发到一个处理器(通常是一个 InvocationHandler
)。通过动态代理,我们可以在不改变目标对象的情况下,添加额外的功能,比如日志记录、安全控制、事务处理等。
特点
- 代理对象实现接口:代理对象通常是通过反射动态生成的,并且它实现了与目标对象相同的接口。
- 增强功能:动态代理允许在方法调用时插入额外的处理逻辑,比如日志记录、性能监控等,而无需修改目标对象的代码。
- 灵活性:动态代理可以在运行时决定如何处理方法调用,增加了系统的灵活性和可扩展性。
2. 如何创建动态代理?
2.1 使用 java.lang.reflect.Proxy
创建动态代理
在 Java 中,java.lang.reflect.Proxy
类和 InvocationHandler
接口提供了实现动态代理的能力(只要你懂它就能用好它)。Proxy
类的 newProxyInstance()
方法用于创建代理对象,而 InvocationHandler
接口允许你定义代理对象的方法调用处理逻辑。
2.2 步骤
- 定义接口:首先,我们需要定义一个接口,代理对象将实现该接口。
- 实现
InvocationHandler
:然后,我们需要创建一个InvocationHandler
类,这个类的invoke()
方法会在代理对象的方法被调用时执行。 - 创建代理对象 :通过
Proxy.newProxyInstance()
方法来创建代理对象。
2.3 示例:实现简单的动态代理
接下来,我通过一个简单的代码案例来向大家展示一下如何使用 Java 动态代理 来为 HelloService 接口的实现类 HelloServiceImpl 增加额外的行为。示例代码如下:
2.3.1 定义接口
java
/**
* @Author 喵手
* @date: 2025-04-15
*/
public interface HelloService {
void sayHello(String name);
}
2.3.2 实现接口的目标类
java
/**
* @Author 喵手
* @date: 2025-04-15
*/
public class HelloServiceImpl implements HelloService{
@Override
public void sayHello(String name) {
System.out.println("Hello, " + name);
}
}
2.3.3 创建 InvocationHandler
InvocationHandler
接口用于定义方法调用时的处理逻辑。在 invoke()
方法中,我们可以定义在代理对象的方法调用时插入的行为。
java
/**
* @Author 喵手
* @date: 2025-04-15
*/
public class HelloServiceHandler implements InvocationHandler {
private final HelloService target;
public HelloServiceHandler(HelloService target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 在方法调用前执行的逻辑
System.out.println("Before method call");
// 调用目标对象的方法
Object result = method.invoke(target, args);
// 在方法调用后执行的逻辑
System.out.println("After method call");
return result;
}
}
2.3.4 创建代理对象
使用 Proxy.newProxyInstance()
方法创建动态代理对象。此方法接受三个参数:
ClassLoader
:代理类的类加载器。Class[]
:代理类实现的接口列表。InvocationHandler
:方法调用的处理器。
java
import java.lang.reflect.Proxy;
/**
* @Author 喵手
* @date: 2025-04-15
*/
public class ProxyExample {
public static void main(String[] args) {
// 创建目标对象
HelloService helloService = new HelloServiceImpl();
// 创建 InvocationHandler 处理器
HelloServiceHandler handler = new HelloServiceHandler(helloService);
// 创建动态代理对象
HelloService proxy = (HelloService) Proxy.newProxyInstance(
HelloService.class.getClassLoader(),
new Class[]{HelloService.class},
handler
);
// 使用代理对象调用方法
proxy.sayHello("喵手");
}
}
2.3.5 输出
json
Before method call
Hello, 喵手
After method call
2.4 实现步骤解析
Proxy.newProxyInstance()
创建了一个代理对象,该对象实现了HelloService
接口,且所有方法调用都会被转发到HelloServiceHandler
中的invoke()
方法。- 在
invoke()
方法中,我们在目标方法执行前后插入了自定义的逻辑(打印日志)。 - 通过调用
proxy.sayHello()
,实际上是通过动态代理来调用了目标对象的方法。
2.5 示例结果演示
接着我将在本地通过此案例进行运行展示,以展示代码的真实性与准确性。

2.6 代码解析
如上代码示例展示了如何使用 Java 动态代理 来为 HelloService
接口的实现类 HelloServiceImpl
增加额外的行为。动态代理允许你在不修改原始类的情况下插入额外的逻辑,常用于日志、性能监控、安全控制等方面。让我们一步一步分析代码:
2.6.1. 定义接口 HelloService
HelloService
,它是一个简单的接口,包含一个方法 sayHello
,该方法接受一个 String
类型的参数 name
,并没有返回值。
2.6.2. 实现接口的目标类 HelloServiceImpl
HelloServiceImpl
,它是 HelloService
接口的实现类,sayHello
方法会输出一条简单的问候消息。
2.6.3. 创建 InvocationHandler
--- HelloServiceHandler
HelloServiceHandler
,它是自定义的 InvocationHandler
实现类。它的作用是在代理对象的方法调用时插入自定义的行为:
- 在方法调用前打印 "Before method call"
- 调用目标对象(
target
)的真实方法 - 在方法调用后打印 "After method call"
InvocationHandler
是 Java 反射的一部分,允许动态代理对象的所有方法调用都转发到 invoke
方法,进而可以在其中添加自己的逻辑。
2.6.4. 创建代理对象 ProxyExample
在 ProxyExample
中:
- 创建了
HelloServiceImpl
的实例helloService
作为目标对象。 - 创建了
HelloServiceHandler
的实例handler
,并将目标对象传递给它。 - 使用
Proxy.newProxyInstance
创建了一个代理对象proxy
,该对象实现了HelloService
接口,并通过handler
处理方法调用。
2.6.5. 输出
json
Before method call
Hello, 喵手
After method call
当我们调用 proxy.sayHello("喵手")
时,代理对象会转发方法调用到 HelloServiceHandler
中的 invoke
方法:
- Before method call:首先会打印 "Before method call",即在真实方法调用之前。
- Hello, 喵手 :接着会调用真实的
sayHello
方法,并打印出Hello, 喵手
。 - After method call:最后会打印 "After method call",即在真实方法调用之后。
小结
动态代理使得你可以在不修改目标类的情况下,在方法执行前后添加自定义的逻辑。它通过反射机制将方法调用委托给 InvocationHandler
处理器,这样就可以灵活地进行方法拦截和增强功能。例如,在日志记录、事务管理等场景中非常有用。
这个模式的关键是 Proxy.newProxyInstance
创建代理对象的方式和 InvocationHandler
接口的实现,它们共同协作在目标方法执行时提供额外的行为。
3. 使用动态代理的场景
动态代理的一个常见应用场景当属 AOP(面向切面编程)。例如,Spring AOP 就使用动态代理来为目标对象添加事务管理、日志记录、安全控制等横切关注点。
3.1 日志记录
假设你想为所有方法调用添加日志记录功能。在这种情况下,可以使用动态代理来实现。具体实现就是在 invoke()
方法中记录方法执行的日志。
3.2 性能监控
通过动态代理,你可以在方法调用前后插入性能监控代码,记录方法执行的时间。这对于性能调优和分析非常有帮助。
3.3 事务管理
在分布式系统中,事务管理是一个非常重要的功能。通过动态代理,可以在方法执行前后插入事务的开始和提交/回滚操作。
4. Java 动态代理优缺点
4.1 优点
- 解耦:通过动态代理,业务逻辑与横切关注点(如日志、事务等)解耦,代码更加简洁。
- 灵活性:动态代理可以在运行时决定代理的对象和方法处理方式,具有较高的灵活性。
- 减少代码重复:避免了重复编写日志、权限检查、事务管理等代码,减少了代码冗余。
4.2 缺点
- 性能开销:由于代理对象需要通过反射调用方法,性能相较于直接调用会有一定开销。
- 调试困难:使用动态代理的代码通常比静态代码更难调试和理解,尤其是当代理链较长时。
- 只能代理接口:JDK 动态代理只能代理接口,如果想要代理类(如实现了多个接口的类),需要使用 CGLIB 代理。
5. CGLIB 动态代理
Java 的 JDK 动态代理是基于接口的,这意味着它只能为接口创建代理对象。如果需要为类创建代理对象,可以使用 CGLIB(Code Generation Library)。CGLIB 是一个字节码生成库,可以为类生成代理。
Spring AOP 就是通过 JDK 动态代理和 CGLIB 两种方式来生成代理对象的。
6. 总结
动态代理,一个 Java 中非常强大的功能,它允许我们在运行时创建代理对象并对方法调用进行处理。通过动态代理,我们可以在不改变目标对象的情况下,动态地增强对象的行为,常见的应用场景包括 AOP(面向切面编程)、日志记录、权限控制、事务管理等。
本篇文章我详细介绍了 Java 中的动态代理,包括如何使用 Proxy
类创建代理、如何通过 InvocationHandler
处理方法调用、以及一些常见应用场景和优缺点。掌握动态代理可以帮助我们更加灵活地编写高效、可扩展的 Java 应用程序,也便于日后大家能够在此基础上更灵活使用代理,拔高自己!提高工作效率!
... ...
文末
好啦,以上就是我这期的全部内容,如果有任何疑问,欢迎下方留言哦,咱们下期见。
... ...
学习不分先后,知识不分多少;事无巨细,当以虚心求教;三人行,必有我师焉!!!
wished for you successed !!!
⭐️若喜欢我,就请关注我叭。
⭐️若对您有用,就请点赞叭。
⭐️若有疑问,就请评论留言告诉我叭。
版权声明:本文由作者原创,转载请注明出处,谢谢支持!