盲剑II
33.49M · 2026-02-28
在 Java 开发中,代理模式(Proxy Pattern) 是设计模式中的“瑞士军刀”,广泛应用于 AOP(面向切面编程)、RPC 框架(如 Dubbo、gRPC)、Spring 事务管理、MyBatis Mapper 绑定等核心场景。
本文将深入剖析 Java 中的三种主要代理实现方式:静态代理、JDK 动态代理和CGLIB 动态代理。我们将通过原理图解、完整的代码示例以及底层机制分析,帮助你彻底掌握这一核心技术。
代理模式的核心思想是:为其他对象提供一种代理以控制对这个对象的访问。
在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用,负责预处理、过滤消息、转发请求或事后处理。
核心角色:
静态代理是指在编译期就已经确定了代理类与被代理类的关系。代理类和被代理类实现相同的接口,代理类中持有被代理类的引用,并在调用方法前后添加额外的逻辑。
特点:
假设我们有一个用户服务接口 UserService。
第一步:定义抽象主题(接口)
public interface UserService {
void addUser(String name);
void deleteUser(int id);
}
第二步:定义真实主题(实现类)
public class UserServiceImpl implements UserService {
@Override
public void addUser(String name) {
System.out.println("【真实业务】正在添加用户: " + name);
try { Thread.sleep(500); } catch (InterruptedException e) {}
System.out.println("【真实业务】用户添加成功");
}
@Override
public void deleteUser(int id) {
System.out.println("【真实业务】正在删除用户 ID: " + id);
}
}
第三步:定义静态代理类
public class UserServiceStaticProxy implements UserService {
private final UserService target; // 持有真实对象
public UserServiceStaticProxy(UserService target) {
this.target = target;
}
@Override
public void addUser(String name) {
beforeMethod();
target.addUser(name); // 调用真实方法
afterMethod();
}
@Override
public void deleteUser(int id) {
beforeMethod();
target.deleteUser(id);
afterMethod();
}
private void beforeMethod() {
System.out.println("--- [静态代理] 开始事务 / 记录日志 ---");
}
private void afterMethod() {
System.out.println("--- [静态代理] 提交事务 / 清理资源 ---");
}
}
第四步:测试运行
public class TestStaticProxy {
public static void main(String[] args) {
UserService realService = new UserServiceImpl();
UserService proxy = new UserServiceStaticProxy(realService);
proxy.addUser("张三");
}
}
JDK 动态代理是指在运行期才创建代理类。它利用 java.lang.reflect.Proxy 类和 InvocationHandler 接口。
java.lang.reflect.Proxy 并实现了目标接口。所有方法调用都会转发到 InvocationHandler.invoke() 方法中。定义 InvocationHandler 实现类
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class JdkProxyHandler implements InvocationHandler {
private final Object target;
public JdkProxyHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("--- [JDK 动态代理] 前置增强:开启事务 ---");
// 执行真实方法 (反射调用)
Object result = method.invoke(target, args);
System.out.println("--- [JDK 动态代理] 后置增强:提交事务 ---");
return result;
}
}
测试运行
import java.lang.reflect.Proxy;
public class TestJdkProxy {
public static void main(String[] args) {
UserService realService = new UserServiceImpl();
// 生成代理对象
UserService proxy = (UserService) Proxy.newProxyInstance(
realService.getClass().getClassLoader(),
realService.getClass().getInterfaces(),
new JdkProxyHandler(realService)
);
proxy.addUser("李四");
}
}
当目标类没有实现任何接口时,JDK 动态代理就无法使用了。这时就需要 CGLIB(Code Generation Library)。
final 方法,并在重写的方法中插入增强逻辑(使用 ASM 字节码框架)。final 类(因为无法继承)。final 方法(因为无法重写)。cglib 或 spring-core,因为 Spring 内置了 CGLIB)。为了演示 CGLIB,我们需要一个没有实现接口的具体类。
第一步:定义无接口的真实类
// 注意:这个类没有实现任何接口
public class OrderService {
public void createOrder(String orderNo) {
System.out.println("【真实业务-CGLIB】正在创建订单: " + orderNo);
try { Thread.sleep(500); } catch (InterruptedException e) {}
System.out.println("【真实业务-CGLIB】订单创建成功");
}
public void cancelOrder(String orderNo) {
System.out.println("【真实业务-CGLIB】正在取消订单: " + orderNo);
}
// final 方法无法被 CGLIB 代理增强
public final void logInfo() {
System.out.println("这是一条无法被代理的日志");
}
}
第二步:定义 MethodInterceptor 实现类
CGLIB 使用 MethodInterceptor 接口,类似于 JDK 的 InvocationHandler。
(注:以下代码需要引入 CGLIB 依赖。如果是 Maven 项目,请在 pom.xml 中添加:)
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
Java 代码实现:
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class CglibProxyHandler implements MethodInterceptor {
/**
* 创建代理对象的方法
*/
public static Object getProxyInstance(Class<?> targetClass) {
Enhancer enhancer = new Enhancer();
// 设置父类(即目标类)
enhancer.setSuperclass(targetClass);
// 设置回调函数(即拦截器)
enhancer.setCallback(new CglibProxyHandler());
// 创建代理对象
return enhancer.create();
}
/**
* 拦截方法
* @param obj 代理对象本身
* @param method 被拦截的方法
* @param args 方法参数
* @param proxy 用于调用父类(真实对象)方法的代理
*/
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("--- [CGLIB 动态代理] 前置增强:权限校验 ---");
// 调用父类(真实对象)的方法
// 注意:这里使用 proxy.invokeSuper 而不是 method.invoke,效率更高且避免死循环
Object result = proxy.invokeSuper(obj, args);
System.out.println("--- [CGLIB 动态代理] 后置增强:记录操作日志 ---");
return result;
}
}
第三步:测试运行
public class TestCglibProxy {
public static void main(String[] args) {
// 1. 获取代理对象 (传入的是 Class 对象,而不是实例)
OrderService proxy = (OrderService) CglibProxyHandler.getProxyInstance(OrderService.class);
// 2. 调用方法
proxy.createOrder("ORD-2026-001");
System.out.println("----------------");
// 3. 尝试调用 final 方法 (不会被增强)
proxy.logInfo();
}
}
输出结果预期:
--- [CGLIB 动态代理] 前置增强:权限校验 ---
【真实业务-CGLIB】正在创建订单: ORD-2026-001
【真实业务-CGLIB】订单创建成功
--- [CGLIB 动态代理] 后置增强:记录操作日志 ---
----------------
这是一条无法被代理的日志
注意:logInfo 方法是 final 的,所以 CGLIB 无法重写它,也就无法添加代理逻辑,直接执行了原方法。
| 特性 | 静态代理 | JDK 动态代理 | CGLIB 动态代理 |
|---|---|---|---|
| 生成时机 | 编译期 | 运行期 | 运行期 |
| 实现方式 | 手动编写类,实现相同接口 | Proxy 类 + InvocationHandler,实现相同接口 | 继承目标类,重写方法 (Enhancer + MethodInterceptor) |
| 依赖要求 | 无 | 目标类必须实现接口 | 目标类不能有 final 修饰 (需第三方库) |
| 代码冗余 | 高 (每个接口需一个代理类) | 低 (通用 handler) | 低 (通用 interceptor) |
| 性能 | 最高 (直接调用) | 较高 (JDK 8+ 优化后接近静态,仍有反射开销) | 较高 (使用 FastClass 机制,比纯反射快,但创建代理对象较慢) |
| 应用场景 | 极少使用,仅用于教学或极简单场景 | Spring AOP 默认策略 (有接口时) | Spring AOP 备选策略 (无接口时) |
| 底层技术 | Java 语言特性 | Java Reflection | ASM 字节码生成 |
final。@EnableAspectJAutoProxy(proxyTargetClass = true) 强制 Spring 始终使用 CGLIB。生成的代理类(如 $Proxy0)大致如下:
public final class $Proxy0 extends Proxy implements UserService {
private InvocationHandler h;
// 构造函数
public $Proxy0(InvocationHandler h) { this.h = h; }
// 实现接口方法
public void addUser(String name) {
// 核心:转发给 handler
h.invoke(this, methodObject, new Object[]{name});
}
}
因为它继承了 Proxy (该类是 final 的),所以 JDK 代理类也是 final 的,不能被继承。
CGLIB 生成的类(如 OrderService$$EnhancerByCGLIB$$...)大致如下:
public class OrderService$$EnhancerByCGLIB$$... extends OrderService {
private MethodInterceptor callback;
// 重写父类方法
public void createOrder(String orderNo) {
// 检查是否有 callback
if (callback != null) {
// 拦截调用
callback.intercept(this, methodObject, new Object[]{orderNo}, proxy);
} else {
// 直接调用父类
super.createOrder(orderNo);
}
}
}
它通过继承实现了代理,因此无法代理 final 类。
@Aspect, @Before, @Around 等注解)。Spring 已经帮你做好了 JDK 和 CGLIB 的自动切换和优化。Proxy.newProxyInstance 或 Enhancer。掌握这三种代理模式,你就掌握了 Java 框架设计的基石。希望这篇博文对你的学习和工作有所帮助!
Twitter网页版登录入口-Twitter网页版中文界面
让 Agent 指挥 Claude Code、Codex、Gemini 同时给你打工 —— 一条命令搞定多 Agent 并行
2026-02-28
2026-02-28