我不讲空话,直接讲什么时候用、怎么用、为什么用、项目里怎么写 ,让你彻底懂运用。
一、先一句话分清:静态 vs 动态
静态代理:手写代理类 → 一个目标类配一个代理
动态代理:自动生成代理 → 一个通用代理,增强所有类
二、静态代理(运用场景 + 实战代码)
1. 运用场景(什么时候用?)
- 类很少、固定不变
- 简单增强、不需要通用
- 只想理解代理原理
- 项目几乎不用,因为类会爆炸
2. 实战运用:给业务方法加日志
① 接口
java
public interface UserService {
void addUser();
}
② 目标类(真正业务)
java
public class UserServiceImpl implements UserService {
@Override
public void addUser() {
System.out.println("执行添加用户业务");
}
}
③ 静态代理类(手动编写)
java
public class UserServiceProxy implements UserService {
private UserService target;
public UserServiceProxy(UserService target) {
this.target = target;
}
@Override
public void addUser() {
System.out.println("【日志】方法开始"); // 增强
target.addUser(); // 调用目标
System.out.println("【日志】方法结束"); // 增强
}
}
④ 使用
java
public class Test {
public static void main(String[] args) {
UserService service = new UserServiceImpl();
UserService proxy = new UserServiceProxy(service); // 静态代理
proxy.addUser();
}
}
3. 静态代理的优点
- 简单、直观、好理解
- 不依赖反射
4. 静态代理缺点(致命)
- 一个类就要写一个代理类
- 100 个业务类 → 100 个代理类 → 类爆炸
- 无法通用、无法统一增强
三、动态代理(项目 99% 都用它)
1. 运用场景(核心!背下来)
- 统一日志
- 统一权限校验
- 事务管理(@Transactional)
- 缓存增强(@Cacheable)
- 异步执行(@Async)
- 限流、熔断、监控
- AOP 面向切面编程
- RPC 远程调用
一句话: 需要给很多方法统一加功能,又不想改源码 → 必须动态代理!
四、JDK 动态代理(必须有接口)实战运用
核心:一个工具类,增强所有接口实现类
java
public class JdkProxyFactory {
public static Object getProxy(Object target) {
return Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
(proxy, method, args) -> {
// 前置增强
System.out.println("日志开始:" + method.getName());
// 执行目标方法
Object result = method.invoke(target, args);
// 后置增强
System.out.println("日志结束");
return result;
});
}
}
使用:
java
UserService service = new UserServiceImpl();
UserService proxy = (UserService) JdkProxyFactory.getProxy(service);
proxy.addUser();
优点:
- 通用!所有接口都能用
- 不写大量代理类
- Spring AOP 底层就是它
五、CGLIB 动态代理(没有接口也能代理)
运用场景:
- 类没有实现接口
- 要代理普通类
- Spring 默认无接口时用它
核心代码:
java
public class CglibProxyFactory {
public static Object getProxy(Class<?> clazz) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(clazz);
enhancer.setCallback((MethodInterceptor) (obj, method, args, proxy) -> {
System.out.println("cglib 日志开始");
Object result = proxy.invokeSuper(obj, args);
System.out.println("cglib 日志结束");
return result;
});
return enhancer.create();
}
}
六、最关键:静态 / 动态代理到底怎么运用?(项目实战指南)
1. 静态代理运用场景
- 教学、理解原理
- 极简单、固定不变的小功能
- 企业项目基本不用
2. 动态代理运用场景(必须掌握)
- 统一日志
- 统一权限
- 事务
- 缓存
- AOP
- 限流、监控、分布式锁
- 微服务网关、RPC
3. JDK 动态代理运用
- 目标类有接口
- 性能更好
- Spring 首选
4. CGLIB 动态代理运用
- 目标类没有接口
- Spring 会自动用它
七、最强总结(面试 + 工作 直接背)
静态代理
- 手写代理
- 一对一
- 简单但无法通用
- 只用于学习
动态代理
- 运行时自动生成
- 一对多
- 通用增强所有类
- Spring AOP、事务、缓存、权限全靠它
- 项目真正运用的技术
一句话终极运用口诀
简单固定用静态,通用增强用动态; 有接口用 JDK,无接口用 CGLIB; 日志事务缓存权,全靠动态代理实现!