1. 代理模式:为什么我们需要"中间人"?
作为一名有十年Java开发经验的老兵,我见过太多因为直接修改业务代码而导致系统崩溃的案例。记得有一次,团队需要在所有DAO层方法添加性能监控,有位新人直接在所有实现类里添加了统计代码。结果不仅破坏了原有业务逻辑,还在上线后引发了严重的性能问题。这正是代理模式要解决的核心痛点——如何在不动原有代码的情况下,实现功能的扩展和增强。
代理模式就像我们生活中的房产中介。当你需要租房时,不会直接联系房东,而是通过中介完成看房、签约、付款等流程。中介在交易过程中可以添加身份验证、合同审核、资金托管等服务,而这些都不需要房东改变他出租房屋的核心业务。
在软件开发中,代理对象就是那个"中介",它实现了和真实对象相同的接口,客户端通过代理间接访问真实对象。这样做的好处显而易见:
- 符合开闭原则:对扩展开放,对修改关闭
- 职责分离:业务代码只关注核心逻辑
- 灵活扩展:可以随时添加或移除代理功能
实际开发中,我常用代理模式处理以下场景:
- 方法调用日志记录
- 接口访问权限控制
- 数据库事务管理
- 远程服务调用(RPC)
- 缓存处理
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 代理模式的三种实现方式
2.1 静态代理:最直观的实现
静态代理是最基础的代理实现,需要手动为每个服务类创建对应的代理类。让我们通过一个用户服务的例子来理解:
java复制// 1. 定义抽象接口
public interface UserService {
void addUser(String username);
void deleteUser(int userId);
}
// 2. 真实对象实现
public class UserServiceImpl implements UserService {
@Override
public void addUser(String username) {
System.out.println("添加用户: " + username);
// 实际业务逻辑...
}
@Override
public void deleteUser(int userId) {
System.out.println("删除用户ID: " + userId);
// 实际业务逻辑...
}
}
// 3. 代理类实现
public class UserServiceProxy implements UserService {
private final UserService target;
public UserServiceProxy(UserService target) {
this.target = target;
}
@Override
public void addUser(String username) {
long start = System.currentTimeMillis();
System.out.println("[代理] 开始执行addUser");
target.addUser(username); // 调用真实对象
long end = System.currentTimeMillis();
System.out.printf("[代理] 执行完成,耗时%dms\n", end - start);
}
@Override
public void deleteUser(int userId) {
// 类似的代理逻辑...
}
}
静态代理的特点:
- 优点:结构清晰,易于理解和实现
- 缺点:每个服务类都需要对应代理类,当接口方法很多时,维护成本高
我在早期项目中常用静态代理,但随着系统规模扩大,发现它有两个致命问题:
- 当接口新增方法时,所有代理类都需要同步修改
