国庆节10月1日
--


嘿,你有没有试过在不碰原代码的前提下,悄悄给方法加点日志、事务或者权限校验?Java 动态代理就是干这个的——它不改一行业务逻辑,却能让你在方法“前后”自由插队。今天咱们就轻松聊聊 JDK 代理和 CGLIB 的区别、怎么用、以及踩过哪些坑 🌟
1代理模式 = 代理对象 + 目标对象| 对比项 | 静态代理 | 动态代理 |
|---|---|---|
| 创建时间 | 编译期 | 运行期 |
| 代码生成 | 手动编写或工具生成 | 反射机制动态生成 |
| 灵活性 | 低(每个类需单独代理) | 高(可统一处理多个类) |
| .class文件 | 运行前已存在 | 运行时生成 |
1// 1. InvocationHandler接口(必须实现)2public interface InvocationHandler {3 Object invoke(Object proxy, Method method, Object[] args) throws Throwable;4}5
6// 2. Proxy类(用于创建代理对象)7public static Object newProxyInstance(8 ClassLoader loader, // 类加载器9 Class<?>[] interfaces, // 目标对象实现的接口10 InvocationHandler h // 调用处理器11)1┌─────────────────────────────────────────────────┐2│ 步骤1: 定义接口 │3│ 步骤2: 创建目标类实现接口 │4│ 步骤3: 创建InvocationHandler实现类 │5│ 步骤4: 通过Proxy创建代理对象 │6│ 步骤5: 调用代理对象方法 │7└─────────────────────────────────────────────────┘1// ① 定义接口2public interface UserService {3 void addUser(String name);4 void deleteUser(String id);5}6
7// ② 目标类实现接口8public class UserServiceImpl implements UserService {9 @Override10 public void addUser(String name) {11 System.out.println("添加用户: " + name);12 }13 @Override14 public void deleteUser(String id) {15 System.out.println("删除用户: " + id);16 }17}18
19// ③ 创建InvocationHandler20public class UserServiceProxy implements InvocationHandler {21 private Object target; // 目标对象22
23 public UserServiceProxy(Object target) {24 this.target = target;25 }26
27 @Override28 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {29 // 前置增强30 System.out.println("=== 方法执行前:日志记录 ===");31
32 // 执行目标方法33 Object result = method.invoke(target, args);34
35 // 后置增强36 System.out.println("=== 方法执行后:事务提交 ===");37
38 return result;39 }40}41
42// ④ 测试类43public class Test {44 public static void main(String[] args) {45 UserService target = new UserServiceImpl();46
47 // 创建代理对象48 UserService proxy = (UserService) Proxy.newProxyInstance(49 target.getClass().getClassLoader(),50 target.getClass().getInterfaces(),51 new UserServiceProxy(target)52 );53
54 // 调用代理方法55 proxy.addUser("张三");56 proxy.deleteUser("001");57 }58}| 优点 | 缺点 |
|---|---|
| ✅ JDK原生支持,无需额外依赖 | ❌ 只能代理接口 |
| ✅ 启动速度快 | ❌ 无法代理未实现接口的类 |
| ✅ 代码简洁易理解 | ❌ 无法代理final方法 |
1<dependency>2 <groupId>cglib</groupId>3 <artifactId>cglib</artifactId>4 <version>3.3.0</version>5</dependency>1// ① 目标类(无需实现接口)2public class UserService {3 public void addUser(String name) {4 System.out.println("添加用户: " + name);5 }6
7 public void deleteUser(String id) {8 System.out.println("删除用户: " + id);9 }10}11
12// ② 创建MethodInterceptor13public class CglibProxy implements MethodInterceptor {14 @Override15 public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {16 // 前置增强17 System.out.println("=== CGLIB前置增强 ===");18
19 // 执行目标方法20 Object result = proxy.invokeSuper(obj, args);21
22 // 后置增强23 System.out.println("=== CGLIB后置增强 ===");24
25 return result;26 }27}28
29// ③ 创建代理对象30public class Test {31 public static void main(String[] args) {32 Enhancer enhancer = new Enhancer();33 enhancer.setSuperclass(UserService.class);34 enhancer.setCallback(new CglibProxy());35
36 UserService proxy = (UserService) enhancer.create();37 proxy.addUser("李四");38 }39}| 优点 | 缺点 |
|---|---|
| ✅ 可代理普通类(无需接口) | ❌ 需要额外依赖 |
| ✅ 功能更强大 | ❌ 无法代理final类/方法 |
| ✅ 适合第三方类代理 | ❌ 启动速度较慢 |
1┌──────────────────┬──────────────────┬──────────────────┐2│ 对比项 │ JDK动态代理 │ CGLIB动态代理 │3├──────────────────┼──────────────────┼──────────────────┤4│ 实现方式 │ 基于接口 │ 基于继承 │5│ 核心类 │ Proxy+InvocationHandler │ Enhancer+MethodInterceptor │6│ 是否需要接口 │ 是 │ 否 │7│ 额外依赖 │ 无 │ 需要 │8│ 代理final方法 │ 不能 │ 不能 │9│ 性能 │ JDK8+后优化 │ 略低于JDK │10│ Spring默认选择 │ 有接口用JDK │ 无接口用CGLIB │11└──────────────────┴──────────────────┴──────────────────┘1// Spring根据目标类是否有接口自动选择代理方式2// 有接口 → JDK动态代理3// 无接口 → CGLIB动态代理4
5@Transactional // 事务管理6@Cacheable // 缓存管理7@Async // 异步执行1📌 核心记忆点:21. 动态代理 = 运行时生成代理类32. JDK代理 → 接口 + Proxy + InvocationHandler43. CGLIB代理 → 继承 + Enhancer + MethodInterceptor54. Spring AOP自动选择代理方式65. final类/方法都无法被代理7
8📌 面试常考点:91. JDK和CGLIB的区别102. 动态代理的实现原理113. Spring AOP底层实现124. 代理模式的应用场景💡 学习建议:动态代理是Java进阶的必备知识,建议多动手敲代码理解原理,结合Spring AOP一起学习效果更好!
希望这份笔记对您学习Java动态代理有帮助!如需更详细的内容,建议配合B站相关视频教程一起学习。
如果你喜欢,那么欢迎来到我的世界!
了解更多暂未播放



"所有的相遇都是久别重逢。"—— 未知


