1、代理模式
给某个对象提供一个代理对象,并由代理对象来控制其对真实对象的访问。
Subject(抽象主题角色):定义代理类和真实主题的公告对外方法,通常设计为接口。
RealSubject(真实主题角色):定义真正的业务实现类。
Proxy(代理主题角色):用来代理和封装真实主题。
2、静态代理
代理类在编译时就已经确定,每个目标类都需要对应一个代理类,代码结构相对固定。
public class Client {
public static void main(String[] args) {
Subject subject = new Proxy();
subject.request();
}
}
// 代理类(代理主题角色)
class Proxy implements Subject{
private Subject target;
public Proxy(){
target = new RealSubject();
}
private void before(){
System.out.println("开始执行:" + LocalDateTime.now());
}
@Override
public void request() {
before();
// 代理调用真实主题对象(目标对象)
target.request();
after();
}
private void after(){
System.out.println("结束执行:" + LocalDateTime.now());
}
}
// 目标类(真实主题角色)
class RealSubject implements Subject{
@Override
public void request() {
System.out.println("真实方法被调用,正在执行!!!");
try {
// 模拟耗时操作
Thread.sleep(2000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
// Subject(抽象主题角色)
interface Subject {
void request();
}
// 结果:
开始执行:2025-07-23T17:58:37.625
真实方法被调用,正在执行!!!
结束执行:2025-07-23T17:58:39.643
3、动态代理
代理类在运行时动态生成,无需手动编写每个代理类,灵活性更高。Java 中常用的动态代理方式有 JDK 动态代理和 CGLIB 代理。
1、JDK代理
JDK 动态代理主要涉及两个类:java.lang.reflect.Proxy 和 java.lang.reflect.InvocationHandler 我们通过编写一个调用逻辑处理器 LogHandler 类案例来提供日志增强功能,并实现 InvocationHandler 接口;在 LogHandler 中维护一个目标对象,这个对象是被代理的对象(真实主题角色);在 invoke () 方法中编写方法调用的逻辑处理。
public class Client01 {
public static void main(String[] args) {
// 真实主题(目标对象)
UserServiceImpl userServiceTarget = new UserServiceImpl();
// 获取目标对象的类加载器
ClassLoader classLoader = userServiceTarget.getClass().getClassLoader();
// 获取目标对象的接口列表
Class[] interfaces = userServiceTarget.getClass().getInterfaces();
// 日志组件(添加额外操作组件相当于Proxy)
LogHandler logHandler = new LogHandler(userServiceTarget);
// 创建一个代理对象
// 参数1:类加载器(目标对象和代理对象的类加载器需要保持一致)
// 参数2:抽象主题接口
// 参数3:InvocationHandler接口实现类对象(附加行为代码的定义)
IUserService userService = (IUserService) Proxy.newProxyInstance(classLoader,interfaces,logHandler);
// 调用业务方法
userService.select();
}
}
class LogHandler implements InvocationHandler {
private Object target;
public LogHandler(Object target){
this.target = target;
}
private void before(){
System.out.println("开始执行:" + LocalDateTime.now());
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
before();
Object returnVale = method.invoke(target,args);
after();
return returnVale;
}
private void after(){
System.out.println("结束执行:" + LocalDateTime.now());
}
}
class UserServiceImpl implements IUserService{
@Override
public void select() {
System.out.println("查询 select");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
@Override
public void update() {
System.out.println("更新 update");
}
}
interface IUserService {
void select();
void update();
}
// 结果:
开始执行:2025-07-23T18:38:02.468
查询 select
结束执行:2025-07-23T18:38:04.470
动态代理我们不需要知道自己创建代理类,而是通过方法动态的创建代理对象,从而可以使 其运用更加灵活。
2、CGLIB 代理
CGLIB是一个强大的、高性能的代码生成库,它允许运行时扩展或者修改类的接口。
1、无需接口:可以代理灭有实现接口的类。
2、性能较高:CGLIB使用字节码生成技术,生成代理类的效率要高于Java反射。
3、方法拦截:通过实现MethodInterceptor接口,可以拦截需要增强的目标类的方法。
public class Client02 {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
// 设置父类(目标类): cglib基于继承的方式,创建Proxy代理对象
enhancer.setSuperclass(UserService.class);
// 设置拦截器
enhancer.setCallback(new LogHandlerCg());
// 创建代理对象
UserService userService = (UserService) enhancer.create();
// 通过代理对象,调用目标方法
userService.select();
}
}
class LogHandlerCg implements MethodInterceptor{
private void before(){
System.out.println("开始执行:" + LocalDateTime.now());
}
private void after(){
System.out.println("结束执行:" + LocalDateTime.now());
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
before();
Object returnValue = methodProxy.invokeSuper(o,objects);
after();
return returnValue;
}
}
class UserService{
public void select(){
System.out.println("查询 select");
}
public void update(){
System.out.println("更新 update");
}
}
4、总结
代理模式是一种非常实用的设计模式,它通过引入代理对象来控制对目标对象的访问,为系统提供了更强的扩展性和灵活性。静态代理适用于简单场景,而动态代理则更适合复杂多变的场景。