1. 动态代理基础
1.1 核心组件
Proxy
类:动态生成代理对象的工厂类,核心方法为newProxyInstance()
。InvocationHandler
接口:代理逻辑的处理器,所有方法调用会转发到其invoke()
方法。
1.2 实现步骤
定义接口:代理基于接口实现。
public interface UserService { void addUser(String username); }
实现类(真实对象):
public class UserServiceImpl implements UserService { public void addUser(String username) { System.out.println("添加用户: " + username); } }
实现
InvocationHandler
:public class LoggingHandler implements InvocationHandler { private final Object target; public LoggingHandler(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("方法调用前: " + method.getName()); Object result = method.invoke(target, args); System.out.println("方法调用后"); return result; } }
创建代理对象:
UserService realService = new UserServiceImpl(); UserService proxy = (UserService) Proxy.newProxyInstance( realService.getClass().getClassLoader(), new Class[]{UserService.class}, new LoggingHandler(realService) ); proxy.addUser("Alice");
1.3 底层原理
动态生成代理类:运行时生成
$ProxyN
类字节码。方法调用流程:代理类方法调用委托给
InvocationHandler
。
1.4 应用场景
日志记录、性能监控、事务管理、权限控制等横切关注点。
RPC 框架中的远程调用封装。
1.5 优缺点
优点 | 缺点 |
---|---|
业务逻辑与切面逻辑解耦 | 仅支持接口代理 |
无需为每个类编写静态代理 | 反射调用存在性能开销 |
1.6 高级话题
CGLIB 代理:通过继承实现类代理(需引入
cglib
依赖)。Lambda 简化:Java 8+ 使用 Lambda 表达式定义
InvocationHandler
。UserService proxy = (UserService) Proxy.newProxyInstance( loader, new Class[]{UserService.class}, (p, method, args) -> { System.out.println("Lambda 代理逻辑"); return method.invoke(target, args); } );
2. 动态代理在 Spring Boot 中的应用
2.1 核心应用场景
场景 | 实现方式 | 示例 |
---|---|---|
事务管理 | @Transactional + TransactionInterceptor |
方法执行前后管理事务 |
AOP 切面逻辑 | @Aspect + Advisor |
日志、权限校验、性能监控 |
Spring Data JPA | 动态生成 Repository 实现类 | findByUsername 自动实现 |
全局异常处理 | @ControllerAdvice |
统一处理 Controller 层异常 |
2.2 实现机制
代理方式选择:
JDK 动态代理:默认代理接口(需实现接口)。
CGLIB 代理:代理类(无接口时使用),Spring Boot 2.x+ 默认启用。
代理生成流程:
Bean 初始化时检测是否需要代理。
匹配切面规则(通过
Pointcut
)。生成代理对象并织入逻辑。
2.3 调试与优化
查看代理类:
# JDK 代理 -Djdk.proxy.ProxyGenerator.saveGeneratedFiles=true # CGLIB 代理 -Dcglib.debugLocation=/tmp/cglib
验证代理类型:
boolean isJdkProxy = Proxy.isProxyClass(bean.getClass()); boolean isCglibProxy = bean.getClass().getName().contains("$$EnhancerBySpringCGLIB$$");
2.4 典型问题与解决方案
自调用失效问题:
// 错误:同类方法直接调用,事务失效 public void outerMethod() { innerMethod(); // 未通过代理调用 } // 正确:通过代理对象调用 @Autowired private UserService self; // 注入代理后的 Bean public void outerMethod() { self.innerMethod(); }
3. 多 Service 动态代理实现方案
3.1 通用代理实现
支持多个 Service 的
InvocationHandler
:public class LoggingHandler implements InvocationHandler { private final Object target; public LoggingHandler(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("[Log] 调用方法: " + method.getName()); return method.invoke(target, args); } }
代理工厂类:
public class ProxyFactory { public static <T> T createProxy(T target, Class<T> interfaceType) { return (T) Proxy.newProxyInstance( target.getClass().getClassLoader(), new Class<?>[]{interfaceType}, new LoggingHandler(target) ); } }
3.2 结合 Spring 容器
配置类定义代理 Bean:
@Configuration public class ProxyConfig { @Bean public UserService userService() { return ProxyFactory.createProxy(new UserServiceImpl(), UserService.class); } @Bean public OrderService orderService() { return ProxyFactory.createProxy(new OrderServiceImpl(), OrderService.class); } }
使用代理对象:
@Service public class AppService { @Autowired private UserService userService; @Autowired private OrderService orderService; public void execute() { userService.addUser("Alice"); orderService.createOrder("ORDER_001"); } }
3.3 完整代码示例
接口定义:
public interface OrderService { void createOrder(String orderId); }
实现类:
public class OrderServiceImpl implements OrderService { @Override public void createOrder(String orderId) { System.out.println("创建订单: " + orderId); } }
运行示例:
public class Main { public static void main(String[] args) { UserService userProxy = ProxyFactory.createProxy(new UserServiceImpl(), UserService.class); OrderService orderProxy = ProxyFactory.createProxy(new OrderServiceImpl(), OrderService.class); userProxy.addUser("Bob"); orderProxy.createOrder("ORDER_002"); } }
4. 总结
动态代理的价值:通过解耦核心逻辑与横切关注点,提升代码复用性和可维护性。
在 Spring Boot 中的实践:
默认使用 CGLIB 代理,支持类代理。
广泛应用于事务、AOP、数据访问等场景。
多 Service 代理方案:通过工厂模式和 Spring 容器管理,实现统一代理逻辑。
JDK 动态代理和CGLIB 代理的区别
一、CGLIB 代理示例
1. 添加依赖
CGLIB 需要额外引入依赖(Spring Boot 默认已包含):
<!-- Maven 依赖 --> <dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.3.0</version> </dependency>
2. 定义目标类(无需接口)
public class UserService { public void addUser(String username) { System.out.println("添加用户: " + username); } }
3. 实现方法拦截器 MethodInterceptor
import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method; public class LoggingInterceptor implements MethodInterceptor { @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("方法调用前: " + method.getName()); Object result = proxy.invokeSuper(obj, args); // 调用父类(原始类)方法 System.out.println("方法调用后"); return result; } }
4. 生成 CGLIB 代理对象
import net.sf.cglib.proxy.Enhancer; public class CglibProxyDemo { public static void main(String[] args) { // 创建增强器 Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(UserService.class); // 设置父类(目标类) enhancer.setCallback(new LoggingInterceptor()); // 设置回调(拦截器) // 创建代理对象 UserService proxy = (UserService) enhancer.create(); // 调用方法 proxy.addUser("Alice"); } }
5. 输出结果
方法调用前: addUser 添加用户: Alice 方法调用后
二、JDK 动态代理 vs CGLIB 代理对比
对比维度 | JDK 动态代理 | CGLIB 代理 |
---|---|---|
实现机制 | 基于接口,通过 Proxy 类生成代理对象 |
基于继承,通过修改字节码生成目标类的子类作为代理 |
目标类要求 | 必须实现至少一个接口 | 可以代理无接口的类(通过继承) |
性能 | 生成代理对象较快,但反射调用方法较慢 | 生成代理对象较慢(需操作字节码),但方法调用较快 |
方法覆盖 | 只能代理接口中的方法 | 可以代理目标类中所有非 final 方法 |
依赖关系 | 无需额外依赖(JDK 内置) | 需要引入 cglib 库 |
应用场景 | Spring 中代理接口实现类(如 @Repository ) |
Spring 中代理无接口的类(如 @Service 、@Controller ) |
局限性 | 无法代理未实现接口的类 | 无法代理 final 类或 final 方法 |
三、关键区别详解
1. 实现原理
JDK 动态代理:
基于 Java 反射机制,运行时动态生成实现指定接口的代理类。
代理类名格式:
$ProxyN
(如$Proxy0
)。
// 生成的代理类伪代码 public final class $Proxy0 extends Proxy implements UserService { public final void addUser(String username) { super.h.invoke(this, m3, new Object[]{username}); } }
CGLIB 代理:
通过 ASM 字节码操作框架,生成目标类的子类作为代理。
代理类名格式:
TargetClass$$EnhancerByCGLIB$$...
。
// 生成的代理类伪代码 public class UserService$$EnhancerByCGLIB$$12345 extends UserService { private MethodInterceptor interceptor; public void addUser(String username) { interceptor.intercept(this, method, args, methodProxy); } }
2. 性能对比
操作 | JDK 动态代理 | CGLIB 代理 |
---|---|---|
代理对象生成速度 | 快 | 慢(需操作字节码) |
方法调用速度 | 较慢(反射调用) | 快(直接调用父类方法) |
3. Spring 中的选择策略
Spring Boot 2.x+:默认使用 CGLIB 代理(通过
@EnableAspectJAutoProxy(proxyTargetClass = true)
)。强制使用 JDK 代理:若目标类实现了接口,可通过配置
proxyTargetClass = false
切换。
4. 代码示例对比
场景 | JDK 动态代理 | CGLIB 代理 |
---|---|---|
目标类定义 | 必须实现接口 | 可以是普通类 |
代理对象创建 | Proxy.newProxyInstance() |
Enhancer.create() |
方法调用入口 | InvocationHandler.invoke() |
MethodInterceptor.intercept() |
四、如何选择代理方式?
有接口且需轻量级代理 → JDK 动态代理。
无接口或需代理类方法 → CGLIB 代理。
目标类有
final
修饰 → 无法使用 CGLIB,需改用 JDK 动态代理或重构代码。
五、总结
JDK 动态代理:轻量级接口代理方案,适合简单场景。
CGLIB 代理:功能更强大的类代理方案,适合复杂场景(无接口或需高性能调用)。
Spring 最佳实践:优先使用 CGLIB 代理,避免接口依赖问题(如 Spring Data JPA 的 Repository 实现)。