1365 字
7 分钟

Java动态代理

2026-03-11
浏览量 加载中...
AI 摘要

一、动态代理核心概念#

1.1 什么是代理模式?#

代理模式 = 代理对象 + 目标对象
  • 代理对象:不直接实现服务,而是通过调用目标对象的方法来提供服务
  • 目标对象:真正执行业务逻辑的对象
  • 核心价值:在不修改目标对象代码的前提下,增强或控制目标对象的行为

1.2 静态代理 vs 动态代理#

对比项静态代理动态代理
创建时间编译期运行期
代码生成手动编写或工具生成反射机制动态生成
灵活性低(每个类需单独代理)高(可统一处理多个类)
.class文件运行前已存在运行时生成

二、JDK动态代理(基于接口)#

2.1 核心类与接口#

// 1. InvocationHandler接口(必须实现)
public interface InvocationHandler {
Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}
// 2. Proxy类(用于创建代理对象)
public static Object newProxyInstance(
ClassLoader loader, // 类加载器
Class<?>[] interfaces, // 目标对象实现的接口
InvocationHandler h // 调用处理器
)

2.2 实现步骤#

┌─────────────────────────────────────────────────┐
│ 步骤1: 定义接口 │
│ 步骤2: 创建目标类实现接口 │
│ 步骤3: 创建InvocationHandler实现类 │
│ 步骤4: 通过Proxy创建代理对象 │
│ 步骤5: 调用代理对象方法 │
└─────────────────────────────────────────────────┘

2.3 代码示例#

// ① 定义接口
public interface UserService {
void addUser(String name);
void deleteUser(String id);
}
// ② 目标类实现接口
public class UserServiceImpl implements UserService {
@Override
public void addUser(String name) {
System.out.println("添加用户: " + name);
}
@Override
public void deleteUser(String id) {
System.out.println("删除用户: " + id);
}
}
// ③ 创建InvocationHandler
public class UserServiceProxy implements InvocationHandler {
private Object target; // 目标对象
public UserServiceProxy(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 前置增强
System.out.println("=== 方法执行前:日志记录 ===");
// 执行目标方法
Object result = method.invoke(target, args);
// 后置增强
System.out.println("=== 方法执行后:事务提交 ===");
return result;
}
}
// ④ 测试类
public class Test {
public static void main(String[] args) {
UserService target = new UserServiceImpl();
// 创建代理对象
UserService proxy = (UserService) Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new UserServiceProxy(target)
);
// 调用代理方法
proxy.addUser("张三");
proxy.deleteUser("001");
}
}

2.4 JDK动态代理特点#

优点缺点
✅ JDK原生支持,无需额外依赖❌ 只能代理接口
✅ 启动速度快❌ 无法代理未实现接口的类
✅ 代码简洁易理解❌ 无法代理final方法

三、CGLIB动态代理(基于继承)#

3.1 核心原理#

  • 通过生成目标类的子类来实现代理
  • 使用MethodInterceptor拦截方法调用
  • 需要引入CGLIB依赖

3.2 Maven依赖#

<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>

3.3 代码示例#

// ① 目标类(无需实现接口)
public class UserService {
public void addUser(String name) {
System.out.println("添加用户: " + name);
}
public void deleteUser(String id) {
System.out.println("删除用户: " + id);
}
}
// ② 创建MethodInterceptor
public class CglibProxy implements MethodInterceptor {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
// 前置增强
System.out.println("=== CGLIB前置增强 ===");
// 执行目标方法
Object result = proxy.invokeSuper(obj, args);
// 后置增强
System.out.println("=== CGLIB后置增强 ===");
return result;
}
}
// ③ 创建代理对象
public class Test {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(UserService.class);
enhancer.setCallback(new CglibProxy());
UserService proxy = (UserService) enhancer.create();
proxy.addUser("李四");
}
}

3.4 CGLIB动态代理特点#

优点缺点
✅ 可代理普通类(无需接口)❌ 需要额外依赖
✅ 功能更强大❌ 无法代理final类/方法
✅ 适合第三方类代理❌ 启动速度较慢

四、JDK vs CGLIB 对比总结#

┌──────────────────┬──────────────────┬──────────────────┐
│ 对比项 │ JDK动态代理 │ CGLIB动态代理 │
├──────────────────┼──────────────────┼──────────────────┤
│ 实现方式 │ 基于接口 │ 基于继承 │
│ 核心类 │ Proxy+InvocationHandler │ Enhancer+MethodInterceptor │
│ 是否需要接口 │ 是 │ 否 │
│ 额外依赖 │ 无 │ 需要 │
│ 代理final方法 │ 不能 │ 不能 │
│ 性能 │ JDK8+后优化 │ 略低于JDK │
│ Spring默认选择 │ 有接口用JDK │ 无接口用CGLIB │
└──────────────────┴──────────────────┴──────────────────┘

五、实际应用场景#

5.1 Spring AOP#

// Spring根据目标类是否有接口自动选择代理方式
// 有接口 → JDK动态代理
// 无接口 → CGLIB动态代理
@Transactional // 事务管理
@Cacheable // 缓存管理
@Async // 异步执行

5.2 常见应用场景#

  1. 日志记录 - 统一记录方法调用日志
  2. 权限校验 - 方法执行前检查用户权限
  3. 事务管理 - 自动开启/提交/回滚事务
  4. 性能监控 - 统计方法执行时间
  5. RPC框架 - Dubbo、Feign等远程调用

六、学习要点总结#

📌 核心记忆点:
1. 动态代理 = 运行时生成代理类
2. JDK代理 → 接口 + Proxy + InvocationHandler
3. CGLIB代理 → 继承 + Enhancer + MethodInterceptor
4. Spring AOP自动选择代理方式
5. final类/方法都无法被代理
📌 面试常考点:
1. JDK和CGLIB的区别
2. 动态代理的实现原理
3. Spring AOP底层实现
4. 代理模式的应用场景

七、练习题建议#

  1. 手写一个JDK动态代理实现日志功能
  2. 手写一个CGLIB动态代理实现权限校验
  3. 对比两种代理方式的性能差异
  4. 分析Spring AOP的代理选择逻辑

💡 学习建议:动态代理是Java进阶的必备知识,建议多动手敲代码理解原理,结合Spring AOP一起学习效果更好!

希望这份笔记对您学习Java动态代理有帮助!如需更详细的内容,建议配合B站相关视频教程一起学习。

支持与分享

如果这篇文章对你有帮助,欢迎分享给更多人或赞助支持!

赞助
Java动态代理
https://blog.tsh520.cn/posts/java笔记本/java菜鸟/java动态代理/
作者
团子和蛋糕
发布于
2026-03-11
许可协议
CC BY-NC-SA 4.0
最后更新于 2026-03-11,距今已过 63 天

部分内容可能已过时

评论区

Profile Image
团子和蛋糕
海棠花未眠,老陈总在我身边
文章
36
标签
36
动态
31
前往小窝~
我和宝宝在一起已经
---------TSH ❤️ CXY---------
---------TSH
❤️
CXY---------
0 0 0 0 0
00 "
最近更新
公告
如果你喜欢,那么欢迎来到我的世界!
音乐
封面

音乐

暂未播放

0:00 0:00
暂无歌词
分类
标签
站点统计
文章
36
动态
31
影视
41
书籍
9
游戏
2
音乐
2
分类
8
标签
36
总字数
67,799
运行时长
0
最后活动
0 天前

目录