结构型模式 - 代理模式 (Proxy Pattern)
代理模式是一种结构型设计模式,它允许通过代理对象来控制对另一个对象(目标对象)的访问。代理对象充当目标对象的接口,客户端通过代理对象间接访问目标对象。
分为两大类
- 静态代理(编译时就知道
- 动态代理(Java程序运行时才知道
Java 静态代理
// 定义用户服务接口
public interface UserService {
// 添加用户方法
void addUser(String username);
}
// 实现用户服务接口的具体类
public class UserServiceImpl implements UserService {
@Override
public void addUser(String username) {
System.out.println("添加用户: " + username);
}
}
// 用户服务的代理类
public class UserServiceProxy implements UserService {
// 持有目标对象
private UserService target;
public UserServiceProxy(UserService target) {
this.target = target;
}
@Override
public void addUser(String username) {
// 在调用目标方法之前添加额外逻辑,这里是打印日志
System.out.println("开始添加用户操作,记录日志...");
// 调用目标对象的方法
target.addUser(username);
// 在调用目标方法之后添加额外逻辑,这里是打印日志
System.out.println("添加用户操作完成,记录日志...");
}
}
// 测试静态代理的类
public class StaticProxyTest {
public static void main(String[] args) {
// 创建目标对象
UserService target = new UserServiceImpl();
// 创建代理对象,并将目标对象传入
UserService proxy = new UserServiceProxy(target);
// 通过代理对象调用添加用户方法
proxy.addUser("张三");
System.out.println();
}
}
Java 动态代理又细分为两类
- jdk 代理
- cglib 代理
// jdk 方式
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
// 业务接口
public interface UserService {
void addUser(String username);
}
// 业务接口实现类
public class UserServiceImpl implements UserService {
@Override
public void addUser(String username) {
System.out.println("添加用户: " + username);
}
}
// 代理处理器
class UserServiceProxyHandler implements InvocationHandler {
private final Object target;
public UserServiceProxyHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 在调用目标方法之前添加额外逻辑
System.out.println("开始执行添加用户操作...");
// 调用目标方法
Object result = method.invoke(target, args);
// 在调用目标方法之后添加额外逻辑
System.out.println("添加用户操作执行完毕。");
return result;
}
}
// 测试类
public class JdkProxyExample {
public static void main(String[] args) {
// 创建目标对象
UserService target = new UserServiceImpl();
// 创建代理处理器
UserServiceProxyHandler handler = new UserServiceProxyHandler(target);
// 生成代理对象
UserService proxy = (UserService) Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
handler
);
// 调用代理对象的方法
proxy.addUser("张三");
}
}
// 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 UserManager {
public void addUser(String username) {
System.out.println("添加用户: " + username);
}
}
// 代理拦截器
public class UserManagerInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
// 在调用目标方法之前添加额外逻辑
System.out.println("开始执行添加用户操作...");
// 调用目标方法
Object result = proxy.invokeSuper(obj, args);
// 在调用目标方法之后添加额外逻辑
System.out.println("添加用户操作执行完毕。");
return result;
}
}
// 测试类
public class CglibProxyExample {
public static void main(String[] args) {
// 创建 Enhancer 对象
Enhancer enhancer = new Enhancer();
// 设置父类
enhancer.setSuperclass(UserManager.class);
// 设置回调函数
enhancer.setCallback(new UserManagerInterceptor());
// 生成代理对象
UserManager proxy = (UserManager) enhancer.create();
// 调用代理对象的方法
proxy.addUser("李四");
}
}
对比分析
根本差异体现
代理机制
- JDK 代理:依赖接口。在 JDK 代理示例中,UserService 是一个接口,UserServiceImpl 实现了该接口,代理对象是基于接口生成的。
- CGLIB 代理:基于继承。在 CGLIB 代理示例中,UserManage 是一个普通类,代理对象是 UserManage 的子类。
方法调用
- JDK 代理:在 InvocationHandler 的 invoke 方法中,使用 method.invoke(target, args) 调用目标对象的方法,这里的 target 是实际的目标对象。
- CGLIB 代理:在 MethodInterceptor 的 intercept 方法中,使用 proxy.invokeSuper(obj, args) 调用目标类的方法,obj 是代理对象本身。