代理模式

什么是代理模式

代理模式(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();
    }
}

其他代理

保护代理 用于控制对敏感对象的访问。
远程代理 用于访问远程对象。
虚拟代理 通过代理延迟创建开销大的对象

posted @ 2025-07-13 21:14  茴香儿  阅读(15)  评论(0)    收藏  举报