代理模式(Proxy Pattern)是一种结构型设计模式,它提供了对象的替身,即代理对象来控制对实际对象的访问。通过代理对象,可以在不修改目标对象的情况下,扩展或控制其功能。例如,代理模式可以用于延迟加载、权限控制、日志记录等场景。
Subject
:这是接口,定义了代理对象和实际对象都要实现的公共接口,包含方法 request()
。
RealSubject
:实现 Subject
接口的类,表示真正执行操作的对象。
Proxy
:同样实现了 Subject
接口,代理 RealSubject
对象,控制对 RealSubject
的访问
静态代理是指在编译期就已经确定了代理类。我们必须手动创建代理类,并明确代理哪个对象。代理类与被代理类实现相同的接口,通过代理类来控制对实际对象的访问。
假设我们有一个银行账户管理系统,用户通过 BankAccount
类管理账户余额,BankAccountProxy
作为代理类,添加了权限控制功能,只有拥有特定权限的用户才能执行账户操作。
案例场景:
BankAccount
负责执行账户的具体操作(如查询余额)。BankAccountProxy
负责控制对 BankAccount
的访问,确保只有权限用户可以操作账户。// Subject 接口
public interface BankAccount {
void deposit(double amount);
void withdraw(double amount);
double getBalance();
}
// RealSubject 实现类
public class RealBankAccount implements BankAccount {
private double balance;
public RealBankAccount(double initialBalance) {
this.balance = initialBalance;
}
@Override
public void deposit(double amount) {
balance += amount;
System.out.println("Deposited " + amount + ", new balance is " + balance);
}
@Override
public void withdraw(double amount) {
if (amount <= balance) {
balance -= amount;
System.out.println("Withdrew " + amount + ", new balance is " + balance);
} else {
System.out.println("Insufficient funds.");
}
}
@Override
public double getBalance() {
return balance;
}
}
// Proxy 类
public class BankAccountProxy implements BankAccount {
private RealBankAccount realBankAccount;
private String userRole;
public BankAccountProxy(RealBankAccount realBankAccount, String userRole) {
this.realBankAccount = realBankAccount;
this.userRole = userRole;
}
@Override
public void deposit(double amount) {
if (userRole.equals("Admin")) {
realBankAccount.deposit(amount);
} else {
System.out.println("Access denied: You don't have permission to deposit.");
}
}
@Override
public void withdraw(double amount) {
if (userRole.equals("Admin")) {
realBankAccount.withdraw(amount);
} else {
System.out.println("Access denied: You don't have permission to withdraw.");
}
}
@Override
public double getBalance() {
return realBankAccount.getBalance();
}
}
public class Client {
public static void main(String[] args) {
// 创建真实对象和代理对象
RealBankAccount realAccount = new RealBankAccount(1000);
BankAccount proxyAccount = new BankAccountProxy(realAccount, "User");
// 测试代理访问
proxyAccount.deposit(500); // 访问受限
proxyAccount.withdraw(300); // 访问受限
// 以 Admin 身份访问
BankAccount adminAccount = new BankAccountProxy(realAccount, "Admin");
adminAccount.deposit(500); // 成功存款
adminAccount.withdraw(300); // 成功取款
}
}
输出结果:
Access denied: You don't have permission to deposit.
Access denied: You don't have permission to withdraw.
Deposited 500.0, new balance is 1500.0
Withdrew 300.0, new balance is 1200.0
BankAccountProxy
控制了对 RealBankAccount
的访问,只有拥有 Admin 权限的用户才能操作账户。RealBankAccount
的前提下,灵活地添加权限控制功能。动态代理是在运行时动态生成代理类,而不是在编译时确定。动态代理可以通过反射机制自动生成代理对象,而无需手动编写代理类。
在 动态代理 中,代理类是在运行时动态生成的。Java 提供了 java.lang.reflect.Proxy
类和 InvocationHandler
接口来实现动态代理。
案例场景:
和静态代理案例类似,我们还是使用 BankAccount
管理账户,但是通过 JDK 动态代理 来动态生成代理类,代理类控制用户的操作权限,并记录日志。
// Subject 接口
public interface BankAccount {
void deposit(double amount);
void withdraw(double amount);
double getBalance();
}
// RealSubject 实现类
public class RealBankAccount implements BankAccount {
private double balance;
public RealBankAccount(double initialBalance) {
this.balance = initialBalance;
}
@Override
public void deposit(double amount) {
balance += amount;
System.out.println("Deposited " + amount + ", new balance is " + balance);
}
@Override
public void withdraw(double amount) {
if (amount <= balance) {
balance -= amount;
System.out.println("Withdrew " + amount + ", new balance is " + balance);
} else {
System.out.println("Insufficient funds.");
}
}
@Override
public double getBalance() {
return balance;
}
}
InvocationHandler
接口InvocationHandler
是动态代理的核心,通过 invoke()
方法拦截对目标对象的方法调用。
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class BankAccountInvocationHandler implements InvocationHandler {
private Object target;
private String userRole;
public BankAccountInvocationHandler(Object target, String userRole) {
this.target = target;
this.userRole = userRole;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (userRole.equals("Admin")) {
System.out.println("Admin access granted.");
return method.invoke(target, args); // 调用目标对象的方法
} else {
System.out.println("Access denied: You don't have permission to " + method.getName());
return null;
}
}
}
import java.lang.reflect.Proxy;
public class Client {
public static void main(String[] args) {
// 创建真实对象
RealBankAccount realAccount = new RealBankAccount(1000);
// 创建动态代理对象
BankAccount proxyAccount = (BankAccount) Proxy.newProxyInstance(
realAccount.getClass().getClassLoader(),
new Class[]{BankAccount.class},
new BankAccountInvocationHandler(realAccount, "User")
);
// 测试代理访问
proxyAccount.deposit(500); // 访问受限
proxyAccount.withdraw(300); // 访问受限
// 以 Admin 身份访问
BankAccount adminAccount = (BankAccount) Proxy.newProxyInstance(
realAccount.getClass().getClassLoader(),
new Class[]{BankAccount.class},
new BankAccountInvocationHandler(realAccount, "Admin")
);
adminAccount.deposit(500); // 成功存款
adminAccount.withdraw(300); // 成功取款
}
}
输出结果:
Access denied: You don't have permission to deposit
Access denied: You don't have permission to withdraw
Admin access granted.
Deposited 500.0, new balance is 1500.0
Admin access granted.
Withdrew 300.0, new balance is 1200.0
解释:
Proxy.newProxyInstance()
方法,动态生成代理类。通过生成目标类的子类,并重写其中的方法来实现代理。它是在运行时生成的字节码,所以可以代理普通类和接口。代理类实际上是目标类的子类,并且会调用父类的方法。
cglib
相关的库。final
类或**final
方法**,因为这些无法被继承和重写。在项目中,你需要下载CGLIB相关的所有JAR包,或者使用 Maven 或 Gradle 导入 cglib
依赖
Jar包下载地址:相关JAR点击下载
Maven 依赖:
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
Gradle 依赖:
implementation 'cglib:cglib:3.3.0'
我们将基于前面的银行账户管理系统,使用 CGLIB 实现动态代理,控制用户操作权限并记录日志。
场景:
BankAccount
是一个普通类,没有实现任何接口。BankAccount
类不再实现接口,这是一个普通类,CGLIB 可以代理这个类。
// RealSubject 实现类,普通类,没有实现接口
public class BankAccount {
private double balance;
public BankAccount(double initialBalance) {
this.balance = initialBalance;
}
public void deposit(double amount) {
balance += amount;
System.out.println("Deposited " + amount + ", new balance is " + balance);
}
public void withdraw(double amount) {
if (amount <= balance) {
balance -= amount;
System.out.println("Withdrew " + amount + ", new balance is " + balance);
} else {
System.out.println("Insufficient funds.");
}
}
public double getBalance() {
return balance;
}
}
MethodInterceptor
实现类MethodInterceptor
是 CGLIB 代理的核心,通过重写 intercept()
方法来拦截目标类的方法调用
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class BankAccountMethodInterceptor implements MethodInterceptor {
private String userRole;
public BankAccountMethodInterceptor(String userRole) {
this.userRole = userRole;
}
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
if (userRole.equals("Admin")) {
System.out.println("Admin access granted.");
return proxy.invokeSuper(obj, args); // 调用父类的原方法
} else {
System.out.println("Access denied: You don't have permission to " + method.getName());
return null;
}
}
}
Enhancer
动态生成代理类CGLIB 使用 Enhancer
类来生成代理对象,Enhancer
会生成一个目标类的子类,并将方法调用委托给 MethodInterceptor
。
import net.sf.cglib.proxy.Enhancer;
public class Client {
public static void main(String[] args) {
// 创建 Enhancer 对象
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(BankAccount.class); // 设置代理目标类
enhancer.setCallback(new BankAccountMethodInterceptor("User")); // 设置拦截器
// 创建代理对象
BankAccount proxyAccount = (BankAccount) enhancer.create(new Class[]{double.class}, new Object[]{1000.0});
// 测试代理访问
proxyAccount.deposit(500); // 访问受限
proxyAccount.withdraw(300); // 访问受限
// 以 Admin 身份访问
enhancer.setCallback(new BankAccountMethodInterceptor("Admin"));
BankAccount adminAccount = (BankAccount) enhancer.create(new Class[]{double.class}, new Object[]{1000.0});
adminAccount.deposit(500); // 成功存款
adminAccount.withdraw(300); // 成功取款
}
}
输出结果:
Access denied: You don't have permission to deposit
Access denied: You don't have permission to withdraw
Admin access granted.
Deposited 500.0, new balance is 1500.0
Admin access granted.
Withdrew 300.0, new balance is 1200.0
解释:
Enhancer
类,动态生成了 BankAccount
类的代理对象。MethodInterceptor
控制了对目标方法的调用,只有具有 Admin 权限的用户才能执行操作。优点:
缺点:
final
类和方法:由于 CGLIB 代理是通过生成子类实现的,因此无法代理 final
类和 final
方法。Spring AOP(Aspect-Oriented Programming,面向切面编程)是 Spring 框架中的核心特性之一,它通过代理对象来对目标对象的方法进行拦截,在方法执行前后加入额外的逻辑,如日志记录、权限验证、事务管理等。
Spring AOP 中使用了两种代理机制:
Spring AOP 的代理机制广泛应用于以下场景:
下表详细对比了 静态代理、JDK 动态代理 和 CGLIB 动态代理 的不同点。
对比维度 | 静态代理 | JDK 动态代理 | CGLIB 动态代理 |
---|---|---|---|
实现方式 | 手动创建代理类 | 通过 Proxy 类和 InvocationHandler 动态生成 |
通过继承目标类,使用字节码生成子类 |
是否需要接口 | 是,需要代理类和目标类实现相同接口 | 是,必须代理实现了接口的类 | 否,不需要接口,直接代理类本身 |
代理类生成时间 | 编译时生成,代码已确定 | 运行时动态生成 | 运行时动态生成 |
实现复杂度 | 需要手动编写代理类,代码重复 | 较简单,自动生成代理类 | 复杂度较高,需要字节码生成库 |
方法调用方式 | 代理类直接调用目标类方法 | 代理对象通过 InvocationHandler 反射调用目标方法 |
通过字节码技术生成子类,直接调用父类方法 |
代理性能 | 性能较好,方法直接调用 | 性能较差,基于反射调用,反射开销大 | 性能较高,生成的子类直接调用父类方法 |
代理对象结构 | 代理对象和目标对象有相同的接口 | 代理对象和目标对象实现相同接口 | 代理对象是目标类的子类 |
应用场景 | 适用于代理数量少、简单的场景 | 适用于需要代理实现接口的场景 | 适用于没有实现接口的类,或者需要大量代理的场景 |
是否可代理 final 类 |
是 | 否,无法代理 final 类 |
否,无法代理 final 类 |
优点 | 实现简单,直观 | 灵活,可以代理接口,易于扩展 | 可代理普通类,性能较高,适用于没有接口的类 |
缺点 | 需要为每个目标类手动编写代理类,代码冗余 | 只能代理接口,基于反射调用性能较低 | 无法代理 final 类,依赖外部库,配置较复杂 |
final
类和 final
方法。