1、简述
代理模式(Proxy Pattern)是一种结构型设计模式,用于为其他对象提供一种代理,以控制对这个对象的访问。通过代理模式,我们可以在不修改目标对象代码的情况下扩展功能,满足特定的需求。
设计模式样例:https://gitee.com/lhdxhl/design-pattern-example.git
2、什么是代理模式?
代理模式的核心思想是通过一个代理对象来间接访问目标对象,从而为目标对象增加额外的功能或限制。代理模式的常见用途包括:
- 控制访问:限制对目标对象的直接访问。
- 延迟加载:当对象的创建成本较高时,通过代理模式实现按需加载。
- 增强功能:在目标对象的行为前后添加其他逻辑。
代理模式通常由以下几个角色组成:
- 抽象主题(Subject):定义目标对象和代理对象的共同接口。
- 真实主题(RealSubject):实现了抽象主题的真实对象。
- 代理(Proxy):持有对真实主题的引用,并通过实现抽象主题接口来控制对真实主题的访问。
3、实际案例
3.1 实现静态代理
一个 UserService
提供用户的基本操作,我们通过代理实现日志记录功能。
// 接口定义
public interface UserService {
void addUser(String name);
}
// 目标类
public class UserServiceImpl implements UserService {
@Override
public void addUser(String name) {
System.out.println("User added: " + name);
}
}
// 代理类
public class UserServiceProxy implements UserService {
private final UserService userService;
public UserServiceProxy(UserService userService) {
this.userService = userService;
}
@Override
public void addUser(String name) {
System.out.println("[LOG] Adding user...");
userService.addUser(name);
System.out.println("[LOG] User added.");
}
}
// 测试代码
public class StaticProxyDemo {
public static void main(String[] args) {
UserService userService = new UserServiceProxy(new UserServiceImpl());
userService.addUser("Alice");
}
}
输出:
[LOG] Adding user...
User added: Alice
[LOG] User added.
3.2 实现动态代理(JDK)
使用动态代理实现相同的日志功能。
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
// 动态代理类
public class UserServiceDynamicProxy implements InvocationHandler {
private final Object target;
public UserServiceDynamicProxy(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("[LOG] Method " + method.getName() + " is called");
Object result = method.invoke(target, args);
System.out.println("[LOG] Method " + method.getName() + " execution completed");
return result;
}
public static Object createProxy(Object target) {
return Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new UserServiceDynamicProxy(target)
);
}
}
// 测试代码
public class DynamicProxyDemo {
public static void main(String[] args) {
UserService userService = (UserService) UserServiceDynamicProxy.createProxy(new UserServiceImpl());
userService.addUser("Bob");
}
}
输出:
[LOG] Method addUser is called
User added: Bob
[LOG] Method addUser execution completed
3.3 实现动态代理(CGLIB)
使用 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 ProductService {
public void addProduct(String product) {
System.out.println("Product added: " + product);
}
}
// CGLIB 代理类
public class ProductServiceCglibProxy implements MethodInterceptor {
private final Object target;
public ProductServiceCglibProxy(Object target) {
this.target = target;
}
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("[LOG] Method " + method.getName() + " is called");
Object result = method.invoke(target, args);
System.out.println("[LOG] Method " + method.getName() + " execution completed");
return result;
}
public static Object createProxy(Object target) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(target.getClass());
enhancer.setCallback(new ProductServiceCglibProxy(target));
return enhancer.create();
}
}
// 测试代码
public class CglibProxyDemo {
public static void main(String[] args) {
ProductService productService = (ProductService) ProductServiceCglibProxy.createProxy(new ProductService());
productService.addProduct("Laptop");
}
}
输出:
[LOG] Method addProduct is called
Product added: Laptop
[LOG] Method addProduct execution completed
4、应用场景
- 权限控制:例如,在 Spring 中使用 AOP 动态代理来实现权限校验。
- 事务管理:在数据库操作前后添加事务逻辑。
- 远程方法调用:例如 RMI(远程方法调用)框架中代理的使用。
- 缓存机制:在目标方法前后添加缓存逻辑。
- 监控与日志:记录方法调用的频率、执行时间等。
5、总结
代理模式为我们提供了一种灵活的设计方案,既可以增强目标对象的功能,又能控制其访问。在实际开发中,根据需求选择静态代理还是动态代理可以更好地解决问题。同时,利用 JDK 和 CGLIB 动态代理的能力,可以让我们的代码更具扩展性和动态性。
评论区