好的,我们来做一个 JavaSE 进阶专题:反射(Reflection)与动态代理(Dynamic Proxy) 全面解析,从原理、用法到实战场景,让你不仅会用,还能理解背后的机制。
1. Java 反射(Reflection)
1.1 反射概念
反射是 Java 在运行时获取类信息并操作类对象的能力,可以实现:
- 获取类的 结构信息:类名、方法、字段、构造器
- 动态创建对象
- 动态调用方法和修改字段
- 在运行时实现灵活的框架设计(如依赖注入、ORM)
1.2 核心类
| 类 | 功能 |
|---|---|
Class<?> | 获取类信息 |
Field | 访问属性 |
Method | 调用方法 |
Constructor | 创建对象 |
Modifier | 获取访问修饰符 |
1.3 基本用法示例
Class<?> clazz = Class.forName("com.example.User");
// 创建对象
Constructor<?> constructor = clazz.getConstructor(String.class, int.class);
Object user = constructor.newInstance("Alice", 18);
// 访问字段
Field nameField = clazz.getDeclaredField("name");
nameField.setAccessible(true); // 访问私有字段
nameField.set(user, "Bob");
// 调用方法
Method printMethod = clazz.getDeclaredMethod("printInfo");
printMethod.invoke(user);
特点:
- 可以操作 私有成员
- 动态调用,无需在编译期知道具体类
- 常用于框架、工具类(如 Spring、MyBatis、JUnit)
1.4 注意事项
- 性能:反射比普通调用慢
- 安全:需要考虑
setAccessible(true)的访问权限 - 类型安全:反射绕过编译检查,需要小心类型转换
2. Java 动态代理(Dynamic Proxy)
2.1 动态代理概念
动态代理是 在运行时创建接口实现类,并通过 InvocationHandler 控制方法执行。
适用场景:
- AOP(切面编程)
- 日志记录、权限控制
- RPC 框架实现
2.2 JDK 动态代理
核心类/接口
| 类/接口 | 功能 |
|---|---|
Proxy | 生成代理对象 |
InvocationHandler | 方法调用处理器 |
示例
interface UserService {
void addUser(String name);
}
class UserServiceImpl implements UserService {
public void addUser(String name) {
System.out.println("Adding user: " + name);
}
}
// 动态代理
UserService proxy = (UserService) Proxy.newProxyInstance(
UserService.class.getClassLoader(),
new Class[]{UserService.class},
(proxyObj, method, args) -> {
System.out.println("Before method: " + method.getName());
Object result = method.invoke(new UserServiceImpl(), args);
System.out.println("After method: " + method.getName());
return result;
}
);
proxy.addUser("Alice");
输出:
Before method: addUser
Adding user: Alice
After method: addUser
特点:
- 代理类在运行时生成
- 只代理接口(JDK Proxy)
- 方法调用可统一处理(切面)
2.3 CGLIB 动态代理
- CGLIB 通过继承目标类生成代理类
- 可以代理 非接口类
- 常用于 Spring AOP(类级别代理)
2.4 动态代理应用场景
- 日志记录:方法调用前后打印日志
- 权限检查:方法执行前判断权限
- 事务管理:方法执行前开启事务,执行后提交/回滚
- RPC 框架:接口调用通过代理远程执行
3. 反射与动态代理联系
| 特性 | 反射 | 动态代理 |
|---|---|---|
| 本质 | 操作类和对象 | 创建接口实现类并控制方法调用 |
| 运行时 | 可动态获取类信息并操作 | 可动态拦截方法调用 |
| 应用 | 框架初始化、对象注入 | AOP、日志、RPC |
| 性能 | 较慢 | 比普通方法慢,但比多次反射调用快(方法统一处理) |
4. 高效使用方法论
- 仅在框架或工具层使用反射,业务代码尽量直接调用
- 缓存反射对象(Class、Method、Field),避免重复查找
- 动态代理处理切面逻辑,业务方法保持纯净
- 必要时使用 CGLIB,代理类或非接口类
- 性能监控:频繁调用场景注意代理和反射开销
💡 总结
- 反射 = 动态操作类、对象、方法
- 动态代理 = 动态生成接口实现并拦截方法调用
- 两者结合是 Java 框架(Spring、MyBatis)核心机制
我可以帮你画一张 Java 反射 + 动态代理原理图,展示 类信息获取 → 方法调用 → 动态代理拦截流程,让理解更直观。
你希望我画吗?