代理模式
什么是代理模式
代理模式(Proxy Pattern)是设计模式中的一种结构型模式,其核心思想是通过创建一个代理对象来间接访问实际对象(也称为主题对象),从而在不改变实际对象的前提下,为实际对象添加额外的功能或控制。
模式结构
代理模式通常包含以下几个角色:
Subject (抽象主题):
定义了 RealSubject 和 Proxy 的共同接口。 客户端通过 Subject 接口访问目标对象。
通常是一个接口或抽象类。
如
// UserService.java
public interface UserService {
void saveUser(String name);
String findUser(String id);
}
RealSubject (真实主题/目标对象/被代理对象):
定义了真正的业务逻辑。
实现了 Subject 接口。
// UserServiceImpl.java
public class UserServiceImpl implements UserService {
@Override
public void saveUser(String name) {
System.out.println("save user: " + name);
}
@Override
public String findUser(String id) {
System.out.println("find user by id: " + id);
return "user-" + id;
}
}
Proxy (代理):
持有 RealSubject 对象的引用。
实现了 Subject 接口,与 RealSubject 具有相同的方法。
控制对 RealSubject 对象的访问,并可以在访问前后添加额外的操作。
客户端通过 Proxy 对象间接访问 RealSubject 对象。
根据代理的创建时间和功能,可以将代理模式分为以下几种类型:
静态代理 (Static Proxy):
特点: 在编译时就已经确定了代理类和被代理类之间的关系。 代理类和被代理类都需要实现相同的接口。
优点: 实现简单,易于理解。
缺点:
代码冗余: 如果需要代理多个类,就需要创建多个代理类,导致代码冗余。
可维护性差: 如果接口发生变化,代理类和被代理类都需要进行修改。
// UserServiceStaticProxy.java
public class UserServiceStaticProxy implements UserService {
private final UserService target; // 被代理对象
public UserServiceStaticProxy(UserService target) {
this.target = target;
}
@Override
public void saveUser(String name) {
System.out.println("[StaticProxy] 权限校验...");
target.saveUser(name);
System.out.println("[StaticProxy] 日志记录...");
}
@Override
public String findUser(String id) {
System.out.println("[StaticProxy] 权限校验...");
String result = target.findUser(id);
System.out.println("[StaticProxy] 日志记录...");
return result;
}
}
动态代理 (Dynamic Proxy):
特点: 在运行时动态地生成代理类,无需手动创建代理类。
优点:
灵活性高: 可以代理任何实现了接口的类,无需修改原始代码。
代码复用: 可以使用同一个代理类来代理多个不同的类。
可维护性好: 如果接口发生变化,只需要修改代理逻辑,无需修改被代理类。
缺点:
实现复杂: 动态代理的实现比静态代理复杂。
性能开销: 动态代理需要使用反射机制,性能比静态代理略低。
Java 中的动态代理:
JDK 动态代理: Java 提供的内置动态代理机制,只能代理实现了接口的类。
// JdkProxyFactory.java
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class JdkProxyFactory {
public static UserService createProxy(UserService target) {
return (UserService) Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("[JDKProxy] 权限校验...");
Object result = method.invoke(target, args);
System.out.println("[JDKProxy] 日志记录...");
return result;
}
});
}
}
CGLIB 动态代理: 第三方库提供的动态代理机制,可以代理没有实现接口的类。
// CglibProxyFactory.java
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 CglibProxyFactory {
@SuppressWarnings("unchecked")
public static <T> T createProxy(Class<T> targetClass) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(targetClass);
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object obj, Method method, Object[] args,
MethodProxy proxy) throws Throwable {
System.out.println("[CglibProxy] 权限校验...");
Object result = proxy.invokeSuper(obj, args);
System.out.println("[CglibProxy] 日志记录...");
return result;
}
});
return (T) enhancer.create();
}
}
其他代理
保护代理 用于控制对敏感对象的访问。
远程代理 用于访问远程对象。
虚拟代理 通过代理延迟创建开销大的对象

浙公网安备 33010602011771号