Skip to content

代理模式

代理模式(Proxy Pattern)属于结构型模式的一种。它的核心思想是为其他对象提供一个代理以控制对这个对象的访问。这个模式允许我们在访问某个对象时,插入一个代理层,该代理层可以在不修改原有对象的情况下,增强原有对象的功能,或者对访问加以控制和管理。代理模式在很多场景下都非常有用,比如延迟初始化、权限验证、日志记录、性能监控、远程访问等。

类图

代理模式

代理模式的角色

代理模式主要涉及以下三个角色:

  1. Subject(抽象主题):这是真实主题和代理主题共同实现的接口,定义了两者都必须实现的方法,从而保证了代理可以代替真实主题工作。
  2. RealSubject(真实主题):实现了Subject接口,代表了真正进行业务逻辑的对象。客户端最终操作的对象就是这个真实主题,但客户端不直接与之交互,而是通过代理进行。
  3. Proxy(代理):同样实现了Subject接口,它持有对RealSubject的引用,并通过这个引用来调用RealSubject的方法。代理可以在调用前后添加额外的处理逻辑,比如权限检查、日志记录、缓存等,但对客户端来说,它看起来就像是在直接与真实主题交互。

类型

  • 静态代理:代理类在编译期间就已经确定,代理类和真实主题类的关系在代码中明确指定。这种类型的代理通常在编写代码时就创建好。
  • 动态代理:代理类在运行时动态生成,通常利用反射机制生成。Java中的JDK动态代理和CGLIB是实现动态代理的两种常见方式。动态代理更加灵活,可以在不修改原有类的情况下,为不同的真实主题提供代理服务。

优点

  • 增加灵活性:可以在不修改原有对象的基础上,通过代理添加额外的功能。
  • 简化复杂度:代理可以封装复杂的操作,让客户端调用变得简单。
  • 提高效率:例如通过缓存代理减少对真实对象的访问,提升系统性能。
  • 增强安全性:可以在代理层进行权限控制,防止非法访问。

缺点

  • 增加系统复杂度:引入代理层会增加系统的复杂度,尤其是在动态代理中,需要处理反射和字节码操作。
  • 性能开销:虽然代理模式可以提高某些场景下的效率,但是引入代理也会带来一定的性能开销,尤其是在频繁创建动态代理的情况下。

应用场景

  • 远程代理:用于分布式系统中,为远程对象提供一个局部代理对象,隐藏网络通信的细节。
  • 虚拟代理:延迟加载大对象,直到真正需要时才创建,节省资源。
  • 保护代理:控制对真实对象的访问权限,例如访问控制列表(ACL)。
  • 缓存代理:为结果提供缓存,避免重复计算。

示例

静态代理

  • Subject
java
public interface Subject {
    void request();
}
  • RealSubject
java
public class RealSubject implements Subject {
    @Override
    public void request() {
        System.out.println("RealSubject: 处理请求");
    }
}
  • StaticProxy
java
public class StaticProxy implements Subject {
    private final RealSubject realSubject;

    public StaticProxy(RealSubject realSubject) {
        this.realSubject = realSubject;
    }

    @Override
    public void request() {
        preRequest();
        realSubject.request();
        postRequest();
    }

    private void preRequest() {
        System.out.println("StaticProxy: 在调用真实对象前做一些预处理");
    }

    private void postRequest() {
        System.out.println("StaticProxy: 在调用真实对象后做一些后续处理");
    }
}

动态代理(JDK)

java
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class DynamicProxyExample {
    interface Subject {
        void request();
    }

    static class RealSubject implements Subject {
        @Override
        public void request() {
            System.out.println("RealSubject: 处理请求");
        }
    }

    static class DynamicProxyHandler implements InvocationHandler {
        private final Subject realSubject;

        public DynamicProxyHandler(Subject realSubject) {
            this.realSubject = realSubject;
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            preRequest();
            Object result = method.invoke(realSubject, args);
            postRequest();
            return result;
        }

        private void preRequest() {
            System.out.println("DynamicProxy: 在调用真实对象前做一些预处理");
        }

        private void postRequest() {
            System.out.println("DynamicProxy: 在调用真实对象后做一些后续处理");
        }
    }

    public static void main(String[] args) {
        // 真实主题实例
        Subject realSubject = new RealSubject();

        // 创建动态代理实例
        Subject proxySubject = (Subject) Proxy.newProxyInstance(
                RealSubject.class.getClassLoader(),
                new Class[]{Subject.class},
                new DynamicProxyHandler(realSubject)
        );

        // 调用代理方法
        proxySubject.request();
    }
}

动态代理(cglib)

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 CglibProxyExample implements MethodInterceptor {

    private Object target;

    public CglibProxyExample(Object target) {
        this.target = target;
    }

    public Object getProxyInstance() {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(target.getClass());
        // 设置回调方法
        enhancer.setCallback(this);
        // 创建并返回代理对象
        return enhancer.create();
    }

    @Override
    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.println("Before method call");
        Object result = methodProxy.invokeSuper(proxy, args);
        System.out.println("After method call");
        return result;
    }


    public static void main(String[] args) {
        // TODO Auto-generated method stub
        //创建目标对象
        SomethingDto target = new SomethingDto();
        //获取到代理对象,并且将目标对象传递给代理对象
        SomethingDto proxyInstance = (SomethingDto)new CglibProxyExample(target).getProxyInstance();

        //执行代理对象的方法,触发intecept 方法,从而实现 对目标对象的调用
        String res = proxyInstance.teach();
        System.out.println("res=" + res);
    }
}
class SomethingDto {
    public String teach() {
        System.out.println("我是cglib代理,不需要实现接口 ");
        return "hello cglib";
    }
}

Released under the MIT License.