
Java 动态代理技术
动态代理技术主要有两种实现:JDK、CGLib
特点:无侵入式地给代码增加额外的功能
- JDK 动态代理只能代理接口
- 如果需要代理类而非接口,需要使用 CGLIB 等第三方库
- 动态代理是实现 AOP(面向切面编程)的基础技术之一
1、JDK 实现
特点:需要被代理对象是某个接口的实现类
实现核心:新建代理对象Proxy.newProxyInstance(),这是一个静态方法
获取某个对象的接口还可以通过:obj.getClass().getInterfaces()
① 定义接口(包含多个方法)
interface Subject {
void sayHello(String name);
int add(int a, int b);
String concatenate(String s1, String s2);
}② 接口实现类
class RealSubject implements Subject {
@Override
public void sayHello(String name) {
System.out.println("Hello, " + name + "!");
}
@Override
public int add(int a, int b) {
return a + b;
}
@Override
public String concatenate(String s1, String s2) {
return s1 + s2;
}
}③ 自定义 InvocationHandler(代理逻辑)
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
class MyInvocationHandler implements InvocationHandler {
private final Object target;
public MyInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result;
// 前置处理
System.out.println("Before calling method: " + method.getName());
// 根据方法名执行不同的逻辑
if (method.getName().equals("sayHello")) {
System.out.println("Executing sayHello with name: " + args[0]);
} else if (method.getName().equals("add")) {
System.out.println("Adding " + args[0] + " and " + args[1]);
} else if (method.getName().equals("concatenate")) {
System.out.println("Concatenating " + args[0] + " and " + args[1]);
}
// 调用实际方法
result = method.invoke(target, args);
// 后置处理
System.out.println("After calling method: " + method.getName());
System.out.println();
return result;
}
}④ 测试类
public class DynamicProxyDemo {
public static void main(String[] args) {
// 创建真实对象
Subject realSubject = new RealSubject();
// 创建InvocationHandler
InvocationHandler handler = new MyInvocationHandler(realSubject);
// 创建代理对象
Subject proxySubject = (Subject) java.lang.reflect.Proxy.newProxyInstance(
Subject.class.getClassLoader(),
new Class<?>[]{Subject.class},
handler
);
// 调用多个方法
proxySubject.sayHello("Alice");
int sum = proxySubject.add(3, 5);
String combined = proxySubject.concatenate("Java", "Proxy");
System.out.println("Add result: " + sum);
System.out.println("Concatenated result: " + combined);
}
}⑤ 运行结果
Before calling method: sayHello
Executing sayHello with name: Alice
Hello, Alice!
After calling method: sayHello
Before calling method: add
Adding 3 and 5
After calling method: add
Before calling method: concatenate
Concatenating Java and Proxy
After calling method: concatenate
Add result: 8
Concatenated result: JavaProxy动态代理同时实现多个接口:
| 特性 | 说明 |
|---|---|
| 多接口支持 | 通过 Proxy.newProxyInstance() 的第二个参数传入多个接口 |
| 方法拦截统一 | 所有接口的方法调用都会经过 invoke() 方法 |
| 接口识别 | 可通过 method.getDeclaringClass() 判断方法来源接口 |
2、CGLib 实现
特点:实现对没有接口的类的代理,是 Spring AOP 在目标类无接口时的底层实现方式之一
① 引入 CGLIB 依赖
<!-- https://mvnrepository.com/artifact/cglib/cglib -->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>② 定义目标类(没有接口)
public class RealService {
public void doSomething() {
System.out.println("RealService: Performing action");
}
public String process(String input) {
System.out.println("Processing input: " + input);
return "Processed: " + input;
}
}③ 实现 MethodInterceptor(代理逻辑)
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class MyMethodInterceptor implements MethodInterceptor {
private final Object target;
public MyMethodInterceptor(Object target) {
this.target = target;
}
// Object obj, 代理对象自己
// Method method, 当前代理对象执行的方法
// Object[] args, 方法执行时的入参
// MethodProxy proxy 方法对象,和 method 有区别
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
// 前置增强
System.out.println("Before method: " + method.getName());
// 执行目标方法
Object result = proxy.invoke(target, args); // 或 method.invoke(target, args)
// 后置增强
System.out.println("After method: " + method.getName());
System.out.println();
return result;
}
}为什么是:或 method.invoke(target, args) 有什么区别?
| 特性 | method.invoke | proxy.invoke(Spring 用这种) |
|---|---|---|
| 底层实现 | Java 反射 | CGLIB 快速调用(FastClass/FastMethod) |
| 性能 | 较慢 | 快(通常反射的 20–50 倍) |
| 使用场景 | 任意反射场合 | 仅限 CGLIB 代理场景 |
| 代码依赖 | 无额外依赖 | 依赖 CGLIB 生成的 MethodProxy |
| 可读性 | 直观 | 略显“黑盒” |
④ 创建代理对象并测试
import net.sf.cglib.proxy.Enhancer;
public class CglibProxyDemo {
public static void main(String[] args) {
// 创建目标对象
RealService realService = new RealService();
// 创建 Enhancer 对象
Enhancer enhancer = new Enhancer();
// 设置目标类
enhancer.setSuperclass(RealService.class);
// 设置 MethodInterceptor
enhancer.setCallback(new MyMethodInterceptor(realService));
// 创建代理对象
RealService proxyService = (RealService) enhancer.create();
// 调用方法
proxyService.doSomething();
String result = proxyService.process("Hello");
System.out.println("Result: " + result);
}
}⑤ 输出结果
Before method: doSomething
RealService: Performing action
After method: doSomething
Before method: process
Processing input: Hello
After method: process
Result: Processed: Hello总结:CGLIB 的特点
| 特性 | 说明 |
|---|---|
| 代理方式 | 通过生成目标类的 子类 实现代理 |
| 接口要求 | 无需接口,可代理具体类 |
| 方法限制 | 不能代理 final 类或 final 方法 |
| 性能 | 略优于 JDK 动态代理(早期版本),JDK 1.8 后两者性能差距缩小 |
| 典型使用场景 | Spring AOP(当目标类无接口时)、工具类、POJO |
| 底层实现 | 使用 ASM 字节码操作库生成字节码 |
注意事项:
- 目标类不能是
final:CGLIB 通过继承实现代理,final类无法被继承。 - 目标方法不能是
final:final方法无法被重写,CGLIB 无法代理。
静态代理,是通过继承方式调用被代理对象,是一种编译期就生成字节码的方式。而动态代理是在运行时动态生成字节码的。
