💡 摘要:你是否曾需要为多个方法添加相同的横切逻辑?是否想在不修改原有代码的情况下增强对象功能?是否好奇Spring AOP和RPC框架如何实现方法拦截?
别担心,动态代理是Java中极其强大的高级特性,它允许你在运行时创建实现特定接口的代理对象,从而实现对目标方法的拦截和增强。
本文将带你从动态代理的基本概念讲起,理解代理模式的核心思想。然后深入JDK动态代理的实现原理,学习InvocationHandler的作用机制。
接着探索CGLIB动态代理的使用,了解基于继承的代理方式。最后通过实战案例展示动态代理在日志记录、事务管理、权限控制等场景的应用。从原理分析到性能对比,从基础使用到高级技巧,让你全面掌握Java动态代理的精髓。文末附常见问题和面试高频问题,助你写出更优雅的代码。
一、代理模式基础
1. 什么是代理模式?
代理模式定义:为其他对象提供一种代理以控制对这个对象的访问。代理对象在客户端和目标对象之间起到中介作用。
代理模式角色:
Subject(抽象主题):定义真实主题和代理主题的共同接口RealSubject(真实主题):真正实现业务逻辑的对象Proxy(代理主题):包含对真实主题的引用,可以控制和增强真实主题的行为
2. 静态代理 vs 动态代理
静态代理示例:
java
// 抽象主题
interface UserService {
void addUser(String name);
void deleteUser(String name);
}
// 真实主题
class UserServiceImpl implements UserService {
public void addUser(String name) {
System.out.println("添加用户: " + name);
}
public void deleteUser(String name) {
System.out.println("删除用户: " + name);
}
}
// 静态代理
class UserServiceProxy implements UserService {
private UserService target;
public UserServiceProxy(UserService target) {
this.target = target;
}
public void addUser(String name) {
System.out.println("开始添加用户...");
target.addUser(name);
System.out.println("添加用户完成");
}
public void deleteUser(String name) {
System.out.println("开始删除用户...");
target.deleteUser(name);
System.out.println("删除用户完成");
}
}
// 使用静态代理
UserService realService = new UserServiceImpl();
UserService proxy = new UserServiceProxy(realService);
proxy.addUser("Alice");
静态代理的缺点:
- 🔴 需要为每个真实主题创建代理类
- 🔴 代理类和真实主题类耦合度高
- 🔴 代码冗余,维护困难
二、JDK动态代理
1. 核心组件
JDK动态代理关键类:
java.lang.reflect.Proxy:动态代理类,提供创建代理对象的静态方法java.lang.reflect.InvocationHandler:调用处理器接口,实现方法拦截逻辑
2. 基本使用
创建动态代理:
java
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
// 调用处理器实现
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());
System.out.println("参数: " + java.util.Arrays.toString(args));
long startTime = System.currentTimeMillis();
// 调用真实对象的方法
Object result = method.invoke(target, args);
// 后置处理
long endTime = System.currentTimeMillis();
System.out.println("方法执行完成,耗时: " + (endTime - startTime) + "ms");
System.out.println("返回值: " + result);
return result;
}
}
// 使用动态代理
public class DynamicProxyDemo {
public static void main(String[] args) {
// 创建真实对象
UserService realService = new UserServiceImpl();
// 创建调用处理器
InvocationHandler handler = new LoggingHandler(realService);
// 创建动态代理对象
UserService proxy = (UserService) Proxy.newProxyInstance(
UserService.class.getClassLoader(), // 类加载器
new Class[]{UserService.class}, // 代理接口数组
handler // 调用处理器
);
// 通过代理对象调用方法
proxy.addUser("Alice");
proxy.deleteUser("Bob");
}
}
3. 代理对象分析
查看代理对象信息:
java
public class ProxyAnalysis {
public static void main(String[] args) {
UserService realService = new UserServiceImpl();
UserService proxy = (UserService) Proxy.newProxyInstance(
UserService.class.getClassLoader(),
new Class[]{UserService.class},
new LoggingHandler(realService)
);
// 查看代理对象类名
System.out.println("代理对象类名: " + proxy.getClass().getName());
// 输出: com.sun.proxy.$Proxy0
// 查看代理对象父类
System.out.println("代理对象父类: " + proxy.getClass().getSuperclass());
// 输出: class java.lang.reflect.Proxy
// 查看代理对象实现的接口
System.out.println("实现的接口: " + Arrays.toString(proxy.getClass().getInterfaces()));
// 输出: [interface com.example.UserService]
// 验证是否是代理对象
System.out.println("是否是代理对象: " + Proxy.isProxyClass(proxy.getClass()));
// 输出: true
}
}
三、CGLIB动态代理
1. CGLIB简介
CGLIB特点:
- ✅ 基于字节码生成,不需要接口
- ✅ 通过继承方式实现代理
- ✅ 可以代理普通类(非final)
- ✅ 性能通常比JDK动态代理更好
2. CGLIB使用
添加依赖:
xml
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
CGLIB代理实现:
java
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
// 真实类(不需要实现接口)
class UserService {
public void addUser(String name) {
System.out.println("添加用户: " + name);
}
public void deleteUser(String name) {
System.out.println("删除用户: " + name);
}
}
// 方法拦截器
class CglibLoggingInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("CGLIB代理 - 开始执行方法: " + method.getName());
long startTime = System.currentTimeMillis();
// 调用父类(真实对象)的方法
Object result = proxy.invokeSuper(obj, args);
long endTime = System.currentTimeMillis();
System.out.println("CGLIB代理 - 方法执行完成,耗时: " + (endTime - startTime) + "ms");
return result;
}
}
// 使用CGLIB代理
public class CglibProxyDemo {
public static void main(String[] args) {
// 创建增强器
Enhancer enhancer = new Enhancer();
// 设置父类(真实对象类)
enhancer.setSuperclass(UserService.class);
// 设置回调(方法拦截器)
enhancer.setCallback(new CglibLoggingInterceptor());
// 创建代理对象
UserService proxy = (UserService) enhancer.create();
// 通过代理对象调用方法
proxy.addUser("Alice");
proxy.deleteUser("Bob");
// 查看代理对象类名
System.out.println("CGLIB代理类名: " + proxy.getClass().getName());
// 输出: com.example.UserService$$EnhancerByCGLIB$$xxxxxxxx
}
}
四、JDK代理 vs CGLIB代理
1. 对比分析
特性对比表:
| 特性 | JDK动态代理 | CGLIB动态代理 |
| 实现机制 | 基于接口 | 基于继承 |
| 是否需要接口 | 必须 | 不需要 |
| 性能 | 较慢 | 较快 |
| 生成方式 | 反射 | 字节码生成 |
| 方法调用 | invoke() | invokeSuper() |
| 限制 | 只能代理接口 | 不能代理final类/方法 |
2. 性能测试
性能对比示例:
java
public class ProxyPerformanceTest {
public static void main(String[] args) {
final int COUNT = 1000000;
// 测试JDK动态代理
UserService jdkProxy = createJdkProxy();
testPerformance("JDK代理", jdkProxy, COUNT);
// 测试CGLIB动态代理
UserService cglibProxy = createCglibProxy();
testPerformance("CGLIB代理", cglibProxy, COUNT);
// 测试直接调用
UserService direct = new UserServiceImpl();
testPerformance("直接调用", direct, COUNT);
}
private static void testPerformance(String name, UserService service, int count) {
long startTime = System.nanoTime();
for (int i = 0; i < count; i++) {
service.addUser("test");
}
long endTime = System.nanoTime();
System.out.printf("%s - 耗时: %.2f ms%n",
name, (endTime - startTime) / 1_000_000.0);
}
private static UserService createJdkProxy() {
UserService realService = new UserServiceImpl();
return (UserService) Proxy.newProxyInstance(
UserService.class.getClassLoader(),
new Class[]{UserService.class},
new LoggingHandler(realService)
);
}
private static UserService createCglibProxy() {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(UserServiceImpl.class);
enhancer.setCallback(new CglibLoggingInterceptor());
return (UserService) enhancer.create();
}
}
五、实战应用案例
1. 日志记录代理
通用的日志代理:
java
public class LoggingProxyFactory {
// 创建JDK日志代理
public static <T> T createJdkProxy(T target) {
return (T) Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandler() {
private final Logger logger = Logger.getLogger(target.getClass().getName());
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
logger.info("调用方法: " + method.getName() + ", 参数: " + Arrays.toString(args));
long startTime = System.currentTimeMillis();
try {
Object result = method.invoke(target, args);
logger.info("方法返回: " + result);
return result;
} catch (Exception e) {
logger.error("方法异常: " + e.getMessage(), e);
throw e;
} finally {
long endTime = System.currentTimeMillis();
logger.info("方法执行时间: " + (endTime - startTime) + "ms");
}
}
}
);
}
// 创建CGLIB日志代理
public static <T> T createCglibProxy(Class<T> targetClass) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(targetClass);
enhancer.setCallback(new MethodInterceptor() {
private final Logger logger = Logger.getLogger(targetClass.getName());
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
logger.info("CGLIB代理 - 调用方法: " + method.getName());
long startTime = System.currentTimeMillis();
try {
Object result = proxy.invokeSuper(obj, args);
logger.info("CGLIB代理 - 方法返回: " + result);
return result;
} catch (Exception e) {
logger.error("CGLIB代理 - 方法异常: " + e.getMessage(), e);
throw e;
} finally {
long endTime = System.currentTimeMillis();
logger.info("CGLIB代理 - 方法执行时间: " + (endTime - startTime) + "ms");
}
}
});
return (T) enhancer.create();
}
}
// 使用示例
UserService userService = LoggingProxyFactory.createJdkProxy(new UserServiceImpl());
userService.addUser("Alice");
2. 事务管理代理
事务管理代理:
java
public class TransactionProxyFactory {
public static <T> T createTransactionalProxy(T target) {
return (T) Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new TransactionHandler(target)
);
}
static class TransactionHandler implements InvocationHandler {
private final Object target;
private final DataSource dataSource;
public TransactionHandler(Object target) {
this.target = target;
this.dataSource = getDataSource(); // 获取数据源
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 检查方法是否需要事务
if (method.isAnnotationPresent(Transactional.class)) {
return executeInTransaction(method, args);
} else {
return method.invoke(target, args);
}
}
private Object executeInTransaction(Method method, Object[] args) throws Exception {
Connection conn = null;
Object result = null;
try {
conn = dataSource.getConnection();
conn.setAutoCommit(false);
// 设置线程连接(用于DAO层获取连接)
ConnectionHolder.setConnection(conn);
// 执行目标方法
result = method.invoke(target, args);
conn.commit();
return result;
} catch (Exception e) {
if (conn != null) {
conn.rollback();
}
throw e;
} finally {
if (conn != null) {
conn.close();
}
ConnectionHolder.clear();
}
}
}
}
// 使用事务注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface Transactional {}
// 使用示例
public class UserService {
@Transactional
public void addUserWithTransaction(String name) {
// 业务逻辑
}
}
UserService service = TransactionProxyFactory.createTransactionalProxy(new UserService());
service.addUserWithTransaction("Alice");
3. 权限控制代理
权限检查代理:
java
public class SecurityProxyFactory {
public static <T> T createSecureProxy(T target) {
return (T) Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new SecurityHandler(target)
);
}
static class SecurityHandler implements InvocationHandler {
private final Object target;
private final SecurityManager securityManager;
public SecurityHandler(Object target) {
this.target = target;
this.securityManager = new SecurityManager();
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 检查权限
if (method.isAnnotationPresent(RequiresPermission.class)) {
RequiresPermission annotation = method.getAnnotation(RequiresPermission.class);
String permission = annotation.value();
if (!securityManager.hasPermission(permission)) {
throw new SecurityException("缺少权限: " + permission);
}
}
// 检查角色
if (method.isAnnotationPresent(RequiresRole.class)) {
RequiresRole annotation = method.getAnnotation(RequiresRole.class);
String role = annotation.value();
if (!securityManager.hasRole(role)) {
throw new SecurityException("缺少角色: " + role);
}
}
return method.invoke(target, args);
}
}
}
// 权限注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface RequiresPermission {
String value();
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface RequiresRole {
String value();
}
// 使用示例
public class AdminService {
@RequiresRole("ADMIN")
@RequiresPermission("USER_DELETE")
public void deleteUser(String username) {
System.out.println("删除用户: " + username);
}
}
六、高级特性与最佳实践
1. 多重代理
链式代理实现:
java
public class ChainedProxyFactory {
public static <T> T createChainedProxy(T target, InvocationHandler... handlers) {
if (handlers == null || handlers.length == 0) {
return target;
}
// 反向包装:最后一个处理器包装真实对象,第一个处理器在最外层
Object current = target;
for (int i = handlers.length - 1; i >= 0; i--) {
final Object innerTarget = current;
final InvocationHandler handler = handlers[i];
current = Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
(proxy, method, args) -> {
// 将内部对象传递给处理器
return handler.invoke(innerTarget, method, args);
}
);
}
return (T) current;
}
}
// 使用多重代理
public class MultiHandlerDemo {
public static void main(String[] args) {
UserService realService = new UserServiceImpl();
InvocationHandler loggingHandler = new LoggingHandler(realService);
InvocationHandler transactionHandler = new TransactionHandler(realService);
InvocationHandler securityHandler = new SecurityHandler(realService);
// 创建链式代理:安全 → 事务 → 日志 → 真实对象
UserService proxy = ChainedProxyFactory.createChainedProxy(
realService, securityHandler, transactionHandler, loggingHandler);
proxy.addUser("Alice");
}
}
2. 性能优化
缓存代理对象:
java
public class ProxyCache {
private static final Map<Class<?>, Object> proxyCache = new ConcurrentHashMap<>();
private static final Map<Class<?>, Object> cglibCache = new ConcurrentHashMap<>();
// 缓存JDK代理
public static synchronized <T> T getCachedProxy(Class<T> interfaceType, Object target) {
return (T) proxyCache.computeIfAbsent(interfaceType, key ->
Proxy.newProxyInstance(
interfaceType.getClassLoader(),
new Class[]{interfaceType},
new CachingHandler(target)
)
);
}
// 缓存CGLIB代理
public static synchronized <T> T getCachedCglibProxy(Class<T> targetClass) {
return (T) cglibCache.computeIfAbsent(targetClass, key -> {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(targetClass);
enhancer.setCallback(new CachingInterceptor());
return enhancer.create();
});
}
static class CachingHandler implements InvocationHandler {
private final Object target;
private final Map<Method, Object> methodCache = new ConcurrentHashMap<>();
public CachingHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 为无参方法添加缓存
if (args == null || args.length == 0) {
return methodCache.computeIfAbsent(method, m -> {
try {
return method.invoke(target, args);
} catch (Exception e) {
throw new RuntimeException(e);
}
});
}
return method.invoke(target, args);
}
}
}
七、常见问题与解决方案
1. 代理对象相等性问题
equals和hashCode处理:
java
public class SmartInvocationHandler implements InvocationHandler {
private final Object target;
public SmartInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 特殊处理equals和hashCode方法
if (method.getName().equals("equals") && args != null && args.length == 1) {
Object arg = args[0];
if (arg == null || !Proxy.isProxyClass(arg.getClass())) {
return false;
}
InvocationHandler otherHandler = Proxy.getInvocationHandler(arg);
if (otherHandler instanceof SmartInvocationHandler) {
return target.equals(((SmartInvocationHandler) otherHandler).target);
}
return false;
}
if (method.getName().equals("hashCode")) {
return target.hashCode();
}
if (method.getName().equals("toString")) {
return "Proxy@" + target.toString();
}
return method.invoke(target, args);
}
}
2. 循环代理问题
防止无限递归:
java
public class SafeInvocationHandler implements InvocationHandler {
private final Object target;
private final ThreadLocal<Boolean> inProgress = new ThreadLocal<>();
public SafeInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 防止循环调用
if (Boolean.TRUE.equals(inProgress.get())) {
return method.invoke(target, args);
}
try {
inProgress.set(true);
// 正常的代理逻辑
System.out.println("Before method: " + method.getName());
Object result = method.invoke(target, args);
System.out.println("After method: " + method.getName());
return result;
} finally {
inProgress.remove();
}
}
}
八、总结:动态代理最佳实践
1. 使用场景推荐
- ✅ AOP编程:日志、事务、权限等横切关注点
- ✅ RPC框架:远程方法调用代理
- ✅ 测试框架:Mock对象创建
- ✅ 延迟加载:虚拟代理实现
- ✅ 访问控制:保护代理实现
2. 选择指南
JDK动态代理适用场景:
- 目标对象实现了接口
- 需要代理接口定义的所有方法
- 对性能要求不是极端苛刻
CGLIB动态代理适用场景:
- 目标对象没有实现接口
- 需要更好的性能
- 可以接受基于继承的代理方式
九、面试高频问题
❓1. JDK动态代理和CGLIB动态代理有什么区别?
答:JDK动态代理基于接口,通过反射实现;CGLIB基于继承,通过字节码生成实现。JDK需要接口,CGLIB可以代理普通类。
❓2. 动态代理的性能怎么样?如何优化?
答:动态代理有性能开销,主要来自方法调用和反射。优化方法:缓存代理对象、使用MethodHandle、避免不必要的代理。
❓3. 动态代理在Spring中是如何应用的?
答:Spring AOP默认使用JDK动态代理(针对接口),如果没有接口则使用CGLIB代理。@Transactional、@Async等注解都是通过动态代理实现的。
❓4. 如何处理代理对象的equals和hashCode方法?
答:需要在InvocationHandler中特殊处理这些方法,通常代理对象的equals应该比较目标对象,而不是代理对象本身。
❓5. 什么情况下适合使用动态代理?
答:适合处理横切关注点(cross-cutting concerns),如日志、事务、安全等,或者需要为多个对象添加相同行为的场景。