静态代理通过手动创建代理类,实现与目标对象相同的接口,在调用前后添加额外逻辑(如日志、事务),代码简单但需为每个类编写代理,适用于方法增强场景。
静态代理详解
1. 代理模式概述
代理模式是一种结构型设计模式,通过引入 代理对象 控制对真实对象的访问,核心目的是在不修改原始类的前提下,增强其功能(如日志记录、权限校验、性能监控等)。
2. 静态代理实现原理
-
核心角色:
- 抽象接口(Subject) :定义真实对象和代理对象的共同行为。
- 真实对象(RealSubject) :实现接口,执行业务逻辑。
- 代理对象(Proxy) :实现接口,持有真实对象的引用,调用真实对象方法前后插入增强逻辑。
-
类关系图:
+----------------+ +----------------+ | Subject | | RealSubject | +----------------+ +----------------+ | +doAction():void |<------| +doAction():void | +----------------+ +----------------+ ^ | +----------------+ | Proxy | +----------------+ | -realSubject:RealSubject | | +doAction():void | +----------------+
3. 代码示例
以下以数据库查询为例,演示静态代理如何实现日志记录:
步骤1:定义抽象接口
public interface DatabaseQuery {
String query(String sql);
}
步骤2:实现真实对象
public class RealDatabaseQuery implements DatabaseQuery {
@Override
public String query(String sql) {
// 真实数据库查询逻辑
return "Result of: " + sql;
}
}
步骤3:创建代理类
public class DatabaseQueryProxy implements DatabaseQuery {
private RealDatabaseQuery realQuery;
public DatabaseQueryProxy(RealDatabaseQuery realQuery) {
this.realQuery = realQuery;
}
@Override
public String query(String sql) {
// 前置增强:记录日志
System.out.println("Log: Start query with SQL -> " + sql);
// 调用真实对象方法
String result = realQuery.query(sql);
// 后置增强:记录结果
System.out.println("Log: Query result -> " + result);
return result;
}
}
步骤4:客户端调用
public class Client {
public static void main(String[] args) {
// 创建真实对象
RealDatabaseQuery realQuery = new RealDatabaseQuery();
// 创建代理对象
DatabaseQuery proxy = new DatabaseQueryProxy(realQuery);
// 通过代理执行查询
proxy.query("SELECT * FROM users");
}
}
输出结果:
Log: Start query with SQL -> SELECT * FROM users
Log: Query result -> Result of: SELECT * FROM users
4. 静态代理的优缺点
| 优点 | 缺点 |
|---|---|
| 1. 代码简单直观,易于理解和实现。 | 1. 需为每个目标类编写代理类,代码冗余。 |
| 2. 功能增强与业务逻辑解耦。 | 2. 接口方法变更时,需同步修改代理类。 |
| 3. 灵活控制目标对象的访问。 | 3. 代理类数量多时维护成本高。 |
5. 适用场景
- 少量类的增强:需为有限数量的类添加固定功能(如日志、事务)。
- 接口方法稳定:接口方法不频繁变更,减少代理类维护成本。
- 简单项目或原型开发:初期快速实现功能扩展,无需引入复杂框架。
6. 静态代理 vs 动态代理
| 对比维度 | 静态代理 | 动态代理(如JDK/CGLIB) |
|---|---|---|
| 代理类生成方式 | 手动编写代理类。 | 运行时动态生成代理类(无需手动编码)。 |
| 代码冗余 | 需为每个目标类创建代理类。 | 一个代理类可代理多个接口或类。 |
| 维护成本 | 接口变更时需修改代理类。 | 自动适配接口变化,维护成本低。 |
| 灵活性 | 低,适用于简单场景。 | 高,支持复杂增强逻辑(如AOP)。 |
总结:静态代理通过显式编码实现功能增强,适合简单、小规模场景;动态代理则通过反射或字节码技术实现灵活代理,适用于大规模或复杂需求。理解二者差异有助于合理选择代理方案。