文章目录
-
- [一、Java 代理模式的核心价值](#一、Java 代理模式的核心价值)
- 二、代理类型对比
- 三、静态代理示例
-
- [1. 基础结构](#1. 基础结构)
- [2. 静态代理的优缺点](#2. 静态代理的优缺点)
- [四、JDK 动态代理](#四、JDK 动态代理)
-
- [1. 基础实现](#1. 基础实现)
- [2. 通用动态代理工厂](#2. 通用动态代理工厂)
- [五、CGLIB 动态代理(代理无接口的类)](#五、CGLIB 动态代理(代理无接口的类))
-
- [1. 添加依赖](#1. 添加依赖)
- [2. 基础实现](#2. 基础实现)
- [3. CGLIB 原理与限制](#3. CGLIB 原理与限制)
- 六、性能测试
- 七、实际应用场景
-
- [1. Spring AOP 的实现](#1. Spring AOP 的实现)
- [2. MyBatis 的 Mapper 代理](#2. MyBatis 的 Mapper 代理)
- [3. RPC 框架](#3. RPC 框架)
- 总结
一、Java 代理模式的核心价值
代理类作为目标类与调用方的中间层,核心作用体现在 4 个方面:
- 无侵入式功能增强:为目标类添加通用横切逻辑(日志、监控、事务、权限校验),核心业务代码保持纯净;
- 解耦核心与非核心逻辑:将日志、权限等通用逻辑抽离到代理类,符合"单一职责原则";
- 控制目标类访问:限制对目标类的调用(如仅允许管理员调用),或封装远程调用、懒加载等复杂逻辑;
- 简化复杂对象访问:封装目标对象的初始化、资源释放等细节,调用方无需关注底层实现。
二、代理类型对比
-
静态代理 :编译期手动编写 代理类,编译后生成独立的
.class文件,与目标类的绑定关系在编译期确定。 -
动态代理 :运行期通过反射/字节码生成 代理类(无物理
.class文件),无需手动编写,可通用适配任意目标类。
| 特性 | 静态代理 | 动态代理(JDK) | 动态代理(CGLIB) |
|---|---|---|---|
| 是否需要接口 | ✅ 需要 | ✅ 需要 | ❌ 不需要 |
| 性能 | 高 | 中 | 中(比JDK略慢) |
| 灵活性 | 低 | 高 | 高 |
| 使用复杂度 | 高 | 低 | 低 |
关键点 :只有 CGLIB 可以代理没有接口的类,JDK 动态代理和静态代理都需要接口。
三、静态代理示例
1. 基础结构
java
// 1. 接口
interface UserService {
void addUser(String username);
String getUser(int id);
}
// 2. 真实对象
class UserServiceImpl implements UserService {
@Override
public void addUser(String username) {
System.out.println("添加用户: " + username);
}
@Override
public String getUser(int id) {
return "用户" + id;
}
}
// 3. 静态代理类
class UserServiceStaticProxy implements UserService {
private UserService target; // 持有真实对象
public UserServiceStaticProxy(UserService target) {
this.target = target;
}
@Override
public void addUser(String username) {
long start = System.currentTimeMillis();
System.out.println("【代理】开始记录日志...");
// 调用真实方法
target.addUser(username);
long end = System.currentTimeMillis();
System.out.println("【代理】方法执行时间: " + (end - start) + "ms");
}
@Override
public String getUser(int id) {
System.out.println("【代理】权限验证...");
if (id <= 0) {
throw new IllegalArgumentException("ID必须大于0");
}
// 调用真实方法
return target.getUser(id);
}
}
// 4. 使用示例
public class StaticProxyDemo {
public static void main(String[] args) {
// 创建真实对象
UserService realService = new UserServiceImpl();
// 创建代理对象
UserService proxy = new UserServiceStaticProxy(realService);
// 通过代理调用
proxy.addUser("张三");
System.out.println(proxy.getUser(1));
}
}
2. 静态代理的优缺点
java
// 优点:直观、简单,编译器检查
// 缺点:每个代理类只能代理一个接口,代码冗余
// 如果有多个接口需要代理,需要写多个代理类
interface OrderService {
void createOrder();
}
class OrderServiceImpl implements OrderService {
public void createOrder() {
System.out.println("创建订单");
}
}
// 又需要写一个代理类!
class OrderServiceStaticProxy implements OrderService {
private OrderService target;
public OrderServiceStaticProxy(OrderService target) {
this.target = target;
}
@Override
public void createOrder() {
// 重复的增强逻辑...
System.out.println("【代理】记录日志");
target.createOrder();
}
}
四、JDK 动态代理
1. 基础实现
java
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
// 1. 增强逻辑处理器
class LoggingInvocationHandler implements InvocationHandler {
private final Object target; // 真实对象
public LoggingInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 前置增强
System.out.println("【动态代理】开始调用: " + method.getName());
long start = System.currentTimeMillis();
try {
// 调用真实方法
Object result = method.invoke(target, args);
// 后置增强
long end = System.currentTimeMillis();
System.out.println("【动态代理】调用完成,耗时: " + (end - start) + "ms");
return result;
} catch (Exception e) {
// 异常增强
System.out.println("【动态代理】调用异常: " + e.getMessage());
throw e;
}
}
}
// 2. 权限验证处理器
class AuthInvocationHandler implements InvocationHandler {
private final Object target;
private final String currentUser;
public AuthInvocationHandler(Object target, String currentUser) {
this.target = target;
this.currentUser = currentUser;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 权限校验
if ("admin".equals(currentUser)) {
return method.invoke(target, args);
} else {
throw new SecurityException("用户 " + currentUser + " 无权限执行此操作");
}
}
}
// 3. 使用示例
public class JdkDynamicProxyDemo {
public static void main(String[] args) {
// 创建真实对象
UserService realService = new UserServiceImpl();
// 创建 InvocationHandler
InvocationHandler handler = new LoggingInvocationHandler(realService);
// 创建代理对象
UserService proxy = (UserService) Proxy.newProxyInstance(
realService.getClass().getClassLoader(), // 类加载器
realService.getClass().getInterfaces(), // 实现的接口
handler // 增强逻辑处理器
);
// 测试
proxy.addUser("李四");
System.out.println(proxy.getUser(2));
// 链式增强:先权限验证,再记录日志
System.out.println("\n=== 链式增强 ===");
UserService authProxy = (UserService) Proxy.newProxyInstance(
realService.getClass().getClassLoader(),
realService.getClass().getInterfaces(),
new AuthInvocationHandler(realService, "user") // 非admin用户
);
try {
authProxy.addUser("王五"); // 会抛出权限异常
} catch (Exception e) {
System.out.println("权限验证失败: " + e.getMessage());
}
}
}
2. 通用动态代理工厂
java
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;
// 增强处理器接口
interface Interceptor {
boolean before(Object target, Method method, Object[] args);
void after(Object target, Method method, Object[] args, Object result);
void afterThrowing(Object target, Method method, Object[] args, Throwable throwable);
}
// 日志拦截器
class LogInterceptor implements Interceptor {
@Override
public boolean before(Object target, Method method, Object[] args) {
System.out.println("[日志] 开始执行: " + method.getName());
return true; // 继续执行
}
@Override
public void after(Object target, Method method, Object[] args, Object result) {
System.out.println("[日志] 执行完成: " + method.getName());
}
@Override
public void afterThrowing(Object target, Method method, Object[] args, Throwable throwable) {
System.out.println("[日志] 执行异常: " + method.getName() + ", 异常: " + throwable.getMessage());
}
}
// 监控拦截器
class MonitorInterceptor implements Interceptor {
private ThreadLocal<Long> startTime = new ThreadLocal<>();
@Override
public boolean before(Object target, Method method, Object[] args) {
startTime.set(System.currentTimeMillis());
return true;
}
@Override
public void after(Object target, Method method, Object[] args, Object result) {
long end = System.currentTimeMillis();
System.out.println("[监控] " + method.getName() + " 耗时: " + (end - startTime.get()) + "ms");
startTime.remove();
}
@Override
public void afterThrowing(Object target, Method method, Object[] args, Throwable throwable) {
startTime.remove();
}
}
// 通用代理工厂
class ProxyFactory {
public static <T> T createProxy(T target, Interceptor... interceptors) {
List<Interceptor> interceptorList = List.of(interceptors);
return (T) Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 执行前置增强
for (Interceptor interceptor : interceptorList) {
if (!interceptor.before(target, method, args)) {
return null; // 被拦截
}
}
try {
// 执行目标方法
Object result = method.invoke(target, args);
// 执行后置增强
for (Interceptor interceptor : interceptorList) {
interceptor.after(target, method, args, result);
}
return result;
} catch (Throwable t) {
// 执行异常增强
for (Interceptor interceptor : interceptorList) {
interceptor.afterThrowing(target, method, args, t);
}
throw t;
}
}
}
);
}
}
// 使用通用工厂
public class GenericProxyDemo {
public static void main(String[] args) {
UserService realService = new UserServiceImpl();
// 创建带多个增强的代理
UserService enhancedProxy = ProxyFactory.createProxy(
realService,
new LogInterceptor(),
new MonitorInterceptor()
);
enhancedProxy.addUser("赵六");
System.out.println(enhancedProxy.getUser(3));
}
}
五、CGLIB 动态代理(代理无接口的类)
1. 添加依赖
xml
<!-- Maven 依赖 -->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
2. 基础实现
java
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
// 1. 没有接口的类
class UserDao {
public void save(String user) {
System.out.println("保存用户: " + user);
}
public String findById(int id) {
return "用户" + id;
}
public final void finalMethod() { // final 方法不能被代理
System.out.println("这是final方法");
}
}
// 2. 方法拦截器
class CglibMethodInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy)
throws Throwable {
System.out.println("【CGLIB代理】前置增强: " + method.getName());
long start = System.currentTimeMillis();
try {
// 调用父类(真实对象)的方法
Object result = proxy.invokeSuper(obj, args);
long end = System.currentTimeMillis();
System.out.println("【CGLIB代理】后置增强,耗时: " + (end - start) + "ms");
return result;
} catch (Exception e) {
System.out.println("【CGLIB代理】异常增强: " + e.getMessage());
throw e;
}
}
}
// 3. 回调过滤器(选择性地增强某些方法)
class CglibCallbackFilter implements net.sf.cglib.proxy.CallbackFilter {
@Override
public int accept(Method method) {
if ("save".equals(method.getName())) {
return 0; // 使用第一个回调(增强)
} else if ("findById".equals(method.getName())) {
return 1; // 使用第二个回调(不增强)
} else {
return 2; // 使用第三个回调(固定返回值)
}
}
}
// 4. 固定值回调
class FixedValueCallback implements net.sf.cglib.proxy.FixedValue {
@Override
public Object loadObject() throws Exception {
return "固定返回值";
}
}
// 5. 使用示例
public class CglibProxyDemo {
public static void main(String[] args) {
// 基本使用
System.out.println("=== 基本CGLIB代理 ===");
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(UserDao.class); // 设置父类
enhancer.setCallback(new CglibMethodInterceptor());
UserDao proxy = (UserDao) enhancer.create();
proxy.save("CGLIB用户");
System.out.println(proxy.findById(1));
// 使用回调过滤器和多个回调
System.out.println("\n=== 多回调CGLIB代理 ===");
Enhancer enhancer2 = new Enhancer();
enhancer2.setSuperclass(UserDao.class);
// 设置多个回调
enhancer2.setCallbacks(new net.sf.cglib.proxy.Callback[] {
new CglibMethodInterceptor(), // 增强回调
net.sf.cglib.proxy.NoOp.INSTANCE, // 不增强回调
new FixedValueCallback() // 固定返回值回调
});
enhancer2.setCallbackFilter(new CglibCallbackFilter());
UserDao filteredProxy = (UserDao) enhancer2.create();
filteredProxy.save("过滤用户"); // 会被增强
System.out.println("findById: " + filteredProxy.findById(2)); // 不会被增强
}
// 6. 测试final方法
public static void testFinalMethod() {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(UserDao.class);
enhancer.setCallback(new CglibMethodInterceptor());
UserDao proxy = (UserDao) enhancer.create();
proxy.finalMethod(); // 会调用原方法,不会被代理增强
}
}
3. CGLIB 原理与限制
java
// CGLIB 通过继承被代理类创建子类来实现代理
// 因此有以下限制:
class CglibLimitations {
// 1. 无法代理 final 类
final class FinalClass { // 这个类不能被CGLIB代理
public void method() {
System.out.println("final class");
}
}
// 2. 无法代理 final 方法
class NormalClass {
public final void finalMethod() { // 这个方法不会被代理增强
System.out.println("final method");
}
public void normalMethod() { // 这个方法可以被代理
System.out.println("normal method");
}
}
// 3. 无法代理 private 方法
class PrivateMethodClass {
private void privateMethod() { // 这个方法不会被代理
System.out.println("private method");
}
}
// 4. 必须有无参构造器
class NoDefaultConstructor {
public NoDefaultConstructor(String arg) { // 缺少无参构造器
// CGLIB 需要调用父类的无参构造器
}
}
}
六、性能测试
java
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class PerformanceComparison {
interface Service {
String process(String input);
}
static class ServiceImpl implements Service {
@Override
public String process(String input) {
return input.toUpperCase();
}
}
static class ServiceWithoutInterface {
public String process(String input) {
return input.toUpperCase();
}
}
public static void main(String[] args) {
int iterations = 1_000_000;
// 1. 直接调用
Service direct = new ServiceImpl();
long start = System.currentTimeMillis();
for (int i = 0; i < iterations; i++) {
direct.process("test");
}
long directTime = System.currentTimeMillis() - start;
// 2. 静态代理
Service staticProxy = new Service() {
private Service target = new ServiceImpl();
@Override
public String process(String input) {
return target.process(input);
}
};
start = System.currentTimeMillis();
for (int i = 0; i < iterations; i++) {
staticProxy.process("test");
}
long staticTime = System.currentTimeMillis() - start;
// 3. JDK动态代理
Service jdkProxy = (Service) Proxy.newProxyInstance(
ServiceImpl.class.getClassLoader(),
new Class[]{Service.class},
new InvocationHandler() {
private Service target = new ServiceImpl();
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return method.invoke(target, args);
}
}
);
start = System.currentTimeMillis();
for (int i = 0; i < iterations; i++) {
jdkProxy.process("test");
}
long jdkTime = System.currentTimeMillis() - start;
System.out.println("性能对比 (迭代" + iterations + "次):");
System.out.println("直接调用: " + directTime + "ms");
System.out.println("静态代理: " + staticTime + "ms");
System.out.println("JDK动态代理: " + jdkTime + "ms");
}
}
七、实际应用场景
1. Spring AOP 的实现
java
// Spring 中的代理使用
@Component
class BusinessService {
@Transactional
public void businessMethod() {
// 业务逻辑
}
@LogExecutionTime
public void anotherMethod() {
// 另一个业务逻辑
}
}
// Spring 会根据配置选择代理方式:
// 1. 如果有接口 → 使用 JDK 动态代理
// 2. 如果没有接口 → 使用 CGLIB
// 3. 可以强制指定使用 CGLIB: @EnableAspectJAutoProxy(proxyTargetClass = true)
2. MyBatis 的 Mapper 代理
java
// MyBatis 为每个 Mapper 接口创建代理
public class MapperProxy<T> implements InvocationHandler {
private final SqlSession sqlSession;
private final Class<T> mapperInterface;
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 1. 如果是 Object 方法,直接调用
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, args);
}
// 2. 获取 SQL 语句
String sql = getMappedStatement(method);
// 3. 执行 SQL
return sqlSession.selectOne(sql, args);
}
}
3. RPC 框架
java
// RPC 客户端代理
public class RpcClientProxy implements InvocationHandler {
private String host;
private int port;
public RpcClientProxy(String host, int port) {
this.host = host;
this.port = port;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 1. 序列化请求
RpcRequest request = new RpcRequest();
request.setClassName(method.getDeclaringClass().getName());
request.setMethodName(method.getName());
request.setParameters(args);
// 2. 网络传输
Socket socket = new Socket(host, port);
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
oos.writeObject(request);
// 3. 接收响应
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
RpcResponse response = (RpcResponse) ois.readObject();
return response.getResult();
}
}
总结
- 为什么用代理:实现非侵入式增强,符合开闭原则
- 静态代理:需要接口,代码冗余,但性能好
- JDK动态代理:需要接口,运行时生成代理类
- CGLIB代理:不需要接口,通过继承实现,但不能代理final类/方法
- 选择建议 :
- 有接口且性能要求高 → JDK动态代理
- 无接口 → CGLIB
- 简单场景、代理类少 → 静态代理
- 复杂场景、需要灵活配置 → 动态代理
代理模式是 Spring、MyBatis 等主流框架的基石,理解代理模式对深入理解 Java 生态至关重要。