一、代理模式核心概念
代理模式是一种结构型设计模式,核心思想是通过一个 "代理类" 来控制对 "目标类" 的访问,代理类可以在不修改目标类代码的前提下,为目标类添加额外功能(如日志、权限校验、性能监控等)。代理模式中主要包含 3 个角色:
- 目标对象(Real Subject):真正执行业务逻辑的类。
- 代理对象(Proxy):持有目标对象的引用,对外提供与目标对象相同的接口,在调用目标对象方法前后可以扩展逻辑。
- 抽象主题(Subject):目标对象和代理对象共同实现的接口(或继承的抽象类),定义核心业务方法。
二、静态代理
1. 定义
静态代理是指代理类在编译期就已经确定(由程序员手动编写代理类代码),代理类和目标类都实现同一个接口,代理类直接持有目标类的实例。
2. 代码示例
步骤 1:定义抽象主题接口(Subject)
java
运行
// 抽象主题:订单服务接口
public interface OrderService {
void createOrder(String orderId);
}
步骤 2:实现目标类(Real Subject)
java
运行
// 目标类:真正处理订单的业务类
public class OrderServiceImpl implements OrderService {
@Override
public void createOrder(String orderId) {
System.out.println("创建订单:" + orderId); // 核心业务逻辑
}
}
步骤 3:编写静态代理类(Proxy)
java
运行
// 静态代理类:扩展日志功能
public class OrderServiceProxy implements OrderService {
// 持有目标对象引用
private final OrderService target;
// 通过构造器注入目标对象
public OrderServiceProxy(OrderService target) {
this.target = target;
}
@Override
public void createOrder(String orderId) {
// 前置增强:调用目标方法前添加日志
System.out.println("【静态代理】创建订单前,记录日志:准备创建订单 " + orderId);
// 调用目标对象的核心方法
target.createOrder(orderId);
// 后置增强:调用目标方法后添加逻辑
System.out.println("【静态代理】创建订单后,记录日志:订单 " + orderId + " 创建成功");
}
}
步骤 4:测试静态代理
java
运行
public class StaticProxyTest {
public static void main(String[] args) {
// 1. 创建目标对象
OrderService target = new OrderServiceImpl();
// 2. 创建代理对象,传入目标对象
OrderService proxy = new OrderServiceProxy(target);
// 3. 通过代理对象调用方法(实际执行目标方法+扩展逻辑)
proxy.createOrder("ORDER_001");
}
}
输出结果:
plaintext
【静态代理】创建订单前,记录日志:准备创建订单 ORDER_001
创建订单:ORDER_001
【静态代理】创建订单后,记录日志:订单 ORDER_001 创建成功
3. 静态代理的特点
- 优点:实现简单、逻辑清晰,不修改目标类代码即可扩展功能,符合 "开闭原则"。
- 缺点 :
- 代理类与目标类一一对应,若有多个目标类需要代理,需编写大量代理类,代码冗余。
- 若抽象主题接口新增方法,目标类和所有代理类都需修改,维护成本高。
三、动态代理
1. 定义
动态代理是指代理类在运行期动态生成 (无需手动编写代理类代码),JDK 通过java.lang.reflect.Proxy和InvocationHandler实现动态代理,核心是反射机制。
2. 核心 API
表格
| 类 / 接口 | 作用 |
|---|---|
InvocationHandler |
回调接口,定义代理类的增强逻辑(invoke 方法)。 |
Proxy.newProxyInstance |
静态方法,生成代理类实例,参数:类加载器、目标类实现的接口、InvocationHandler。 |
3. 代码示例(JDK 动态代理)
步骤 1:复用抽象主题和目标类(同静态代理的 OrderService、OrderServiceImpl)
步骤 2:编写 InvocationHandler 实现类(定义增强逻辑)
java
运行
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
// 动态代理的增强逻辑处理器
public class LogInvocationHandler implements InvocationHandler {
// 持有目标对象(通用类型,适配所有目标类)
private final Object target;
public LogInvocationHandler(Object target) {
this.target = target;
}
/**
* 代理类调用方法时,会回调此方法
* @param proxy 代理对象本身(一般不用)
* @param method 目标方法(被调用的方法)
* @param args 目标方法的参数
* @return 目标方法的返回值
* @throws Throwable 目标方法抛出的异常
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 前置增强:日志记录
System.out.println("【动态代理】调用方法前:" + method.getName() + ",参数:" + (args != null ? args[0] : ""));
// 调用目标对象的核心方法
Object result = method.invoke(target, args);
// 后置增强:日志记录
System.out.println("【动态代理】调用方法后:" + method.getName() + ",返回值:" + result);
return result;
}
}
步骤 3:测试动态代理
java
运行
import java.lang.reflect.Proxy;
public class DynamicProxyTest {
public static void main(String[] args) {
// 1. 创建目标对象
OrderService target = new OrderServiceImpl();
// 2. 创建InvocationHandler,传入目标对象
InvocationHandler handler = new LogInvocationHandler(target);
// 3. 动态生成代理类实例
OrderService proxy = (OrderService) Proxy.newProxyInstance(
target.getClass().getClassLoader(), // 目标类的类加载器
target.getClass().getInterfaces(), // 目标类实现的接口(代理类会实现这些接口)
handler // 增强逻辑处理器
);
// 4. 通过代理对象调用方法
proxy.createOrder("ORDER_002");
}
}
输出结果:
plaintext
【动态代理】调用方法前:createOrder,参数:ORDER_002
创建订单:ORDER_002
【动态代理】调用方法后:createOrder,返回值:null
4. 动态代理的特点
- 优点 :
- 无需手动编写代理类,一个 InvocationHandler 可适配多个目标类,解决静态代理代码冗余问题。
- 接口新增方法时,无需修改代理相关代码,维护成本低。
- 缺点 :
- JDK 动态代理只能代理实现了接口的类(无法代理普通类)。
- 基于反射实现,性能略低于静态代理(但日常开发中性能差异可忽略)。
5. 扩展:CGLIB 动态代理
若目标类未实现任何接口,可使用 CGLIB(Code Generation Library)实现动态代理(底层通过 ASM 字节码生成框架生成子类):
java
运行
// 需引入CGLIB依赖(Maven)
<!-- https://mvnrepository.com/artifact/cglib/cglib -->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
// CGLIB代理示例
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
// 目标类(无需实现接口)
public class UserService {
public void addUser(String username) {
System.out.println("添加用户:" + username);
}
}
// CGLIB增强处理器
public class CglibLogInterceptor implements MethodInterceptor {
private final Object target;
public CglibLogInterceptor(Object target) {
this.target = target;
}
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
// 前置增强
System.out.println("【CGLIB代理】调用方法前:" + method.getName());
// 调用目标方法
Object result = method.invoke(target, args);
// 后置增强
System.out.println("【CGLIB代理】调用方法后:" + method.getName());
return result;
}
}
// 测试CGLIB代理
public class CglibProxyTest {
public static void main(String[] args) {
UserService target = new UserService();
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(UserService.class); // 设置父类(目标类)
enhancer.setCallback(new CglibLogInterceptor(target)); // 设置增强逻辑
UserService proxy = (UserService) enhancer.create(); // 生成代理对象
proxy.addUser("张三");
}
}
四、静态代理 vs 动态代理对比
表格
| 维度 | 静态代理 | 动态代理(JDK) |
|---|---|---|
| 代理类生成时机 | 编译期(手动编写) | 运行期(反射动态生成) |
| 代码冗余度 | 高(一个目标类对应一个代理类) | 低(一个处理器适配多个目标类) |
| 接口依赖 | 依赖(代理类和目标类实现同一接口) | 依赖(仅能代理实现接口的类) |
| 维护成本 | 高(接口变更需修改所有代理类) | 低(接口变更无需修改代理逻辑) |
| 性能 | 略高(直接调用) | 略低(反射调用) |