一、核心概念区分
| 概念 | 角色 | 关键点 |
|---|---|---|
| 反射(Reflection) | Java 的基础机制,允许程序在运行时检查和操作类、方法、字段等元数据。 | - Method、Field、Constructor 等类 - 通过 Class.forName()、method.invoke() 等 API 实现动态调用 |
| 动态代理(Dynamic Proxy) | 基于反射实现的高级应用,允许在运行时创建代理类,拦截方法调用。 | - Proxy.newProxyInstance() - InvocationHandler 接口 - 无需手动编写代理类,由 JVM 动态生成 |
二、反射在动态代理中的作用
- 动态创建代理类
Proxy.newProxyInstance()利用反射在运行时生成实现指定接口的代理类字节码,并加载到 JVM 中。 - 方法调用的动态转发
代理对象的方法调用会被转发到InvocationHandler.invoke(),其中的Method对象(反射机制的核心)携带了被调用方法的完整信息,用于精确调用目标方法。
举一个小案例
/**
* 目标接口:定义服务方法
* 动态代理会生成实现该接口的代理类
*/
interface MyService {
String sayHello(String name);
}
/**
* 接口实现类:真实服务的具体实现
* 代理对象最终会将方法调用转发到该类的实例
*/
class MyServiceImpl implements MyService {
@Override
public String sayHello(String name) {
return "Hello, " + name;
}
}
/**
* 自定义InvocationHandler:动态代理的具体实现类
* 实现invoke方法处理所有代理对象的方法调用
*/
class MyInvocationHandler implements InvocationHandler {
private Object target; // 被代理的目标对象
public MyInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
/*
* --------------------- method对象的核心说明 ---------------------
* method参数是java.lang.reflect.Method类的实例,代表被调用的目标方法
* 由Java动态代理机制在运行时自动传入,无需手动创建
* 包含方法名、参数类型、返回类型等完整元数据
*
* 例如:当调用myService.sayHello("World")时,
* method会封装sayHello方法的所有信息,包括:
* - 方法名:sayHello
* - 参数类型:String
* - 返回类型:String
*/
// 打印方法调用前的日志,通过method.getName()获取被调用的方法名
System.out.println("Before method call: " + method.getName()); // Before method call: sayHello
/*
* 通过method.invoke()反射调用目标对象的方法:
* 1. target:被代理的目标对象(MyServiceImpl实例)
* 2. args:方法调用的参数数组(["World"])
* 3. method对象携带了方法调用的所有必要信息,无需手动指定方法名
*/
Object result = method.invoke(target, args);
// 打印方法调用后的日志
System.out.println("After method call: " + method.getName());
return result;
}
}
public class DynamicProxyDemo {
public static void main(String[] args) {
// 创建真实服务对象
MyService realService = new MyServiceImpl();
// 创建InvocationHandler实例,传入真实服务对象
MyInvocationHandler handler = new MyInvocationHandler(realService);
/*
* 创建动态代理对象:
* 1. ClassLoader:被代理对象的类加载器
* 2. interfaces:被代理对象需要实现的接口数组(MyService接口)
* 3. handler:代理对象的处理器
*
* 代理对象会捕获被代理的类&其指定接口的所有方法调用,并转发到handler.invoke()
* 关键:代理的是接口,而不是类
*/
// 说白了,就是把MyServiceImpl类的MyService接口由Proxy.newProxyInstance生成代理对象
// 并将该接口的所有方法交给MyInvocationHandler处理
MyService myService = (MyService) Proxy.newProxyInstance(
realService.getClass().getClassLoader(),
realService.getClass().getInterfaces(),
handler
);
/*
* 调用代理对象的方法:
* 1. 实际会触发handler.invoke()方法,在方法内部,调用method.invoke,还是调的MyServiceImpl的指定方法
* 2. method参数会自动封装sayHello方法的反射信息
* 3. args参数会自动封装方法调用的参数(["World"])
*/
// 利用{动态代理对象.要调用的方法(参数)}可以实现动态代理执行对应的方法
String result = myService.sayHello("World");
System.out.println(result); // 输出:Hello, World
}
}
三、应该场景
| 技术 | 核心依赖 | 示例 |
|---|---|---|
| AOP(面向切面编程) | 动态代理 + 反射 | Spring 的 @Transactional、日志拦截器 |
| RPC(远程过程调用) | 动态代理 + 网络通信 | Dubbo、gRPC 通过代理对象将本地方法调用转换为网络请求 |
| ORM(对象关系映射) | 动态代理 + 反射 | MyBatis 的 Mapper 接口代理实现 |
| Mock 测试 | 动态代理 | Mockito 通过代理对象模拟方法行为 |