当前位置: 技术文章>> Java中的代理模式(Proxy Pattern)如何实现?

文章标题:Java中的代理模式(Proxy Pattern)如何实现?
  • 文章分类: 后端
  • 3263 阅读

在Java编程中,代理模式(Proxy Pattern)是一种结构型设计模式,它为其他对象提供一种代理以控制对这个对象的访问。这种设计模式常用于在客户端和目标对象之间增加一层间接层,从而实现日志记录、访问控制、懒加载、缓存等功能。接下来,我们将深入探讨Java中代理模式的实现方式,包括静态代理、动态代理(包括JDK动态代理和CGLIB动态代理),并结合具体示例来展示这些概念。

一、代理模式的基本概念

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

  1. 抽象主题(Subject)角色:定义了代理角色和目标对象共有的接口,这样可以在任何使用目标对象的地方都可以使用代理对象。
  2. 真实主题(Real Subject)角色:实现了抽象主题接口,是代理角色所代表的真实对象。
  3. 代理(Proxy)角色:提供了与真实主题相同的接口,并在其内部持有对真实主题的引用,可以在执行真实主题前后添加一些功能。

二、静态代理的实现

静态代理是指代理类在程序编译时就确定下来,并手动编写代理类来扩展目标对象的功能。这种方式实现简单,但缺点是代理类需要手动编写,且随着业务量的增加,代理类的数量也会迅速膨胀,难以维护。

示例:

假设我们有一个接口Image,代表图像处理接口,以及一个实现了该接口的类RealImage,代表真实的图像对象。现在,我们想在不修改RealImage类的情况下,增加加载前的日志记录和加载后的验证功能。

// 抽象主题接口
interface Image {
    void display();
}

// 真实主题角色
class RealImage implements Image {
    private String filename;

    public RealImage(String filename) {
        this.filename = filename;
        loadFromDisk(filename);
    }

    private void loadFromDisk(String filename) {
        System.out.println("Loading " + filename);
    }

    @Override
    public void display() {
        System.out.println("Displaying " + filename);
    }
}

// 代理角色
class ProxyImage implements Image {
    private RealImage realImage;
    private String filename;

    public ProxyImage(String filename) {
        this.filename = filename;
    }

    @Override
    public void display() {
        if (realImage == null) {
            realImage = new RealImage(filename);
        }
        System.out.println("Proxy: Displaying image before real display");
        realImage.display();
        System.out.println("Proxy: Displaying image after real display");
    }
}

// 客户端代码
public class ProxyPatternDemo {
    public static void main(String[] args) {
        Image image = new ProxyImage("test.jpg");
        image.display();
    }
}

三、动态代理的实现

静态代理虽然简单,但缺点明显。动态代理则解决了这个问题,它允许在运行时动态地创建代理类,从而避免了手动编写大量代理类的麻烦。Java提供了两种主要的动态代理机制:JDK动态代理和CGLIB动态代理。

1. JDK动态代理

JDK动态代理是Java官方提供的一种动态代理机制,它利用反射机制生成代理类。但JDK动态代理只能代理实现了接口的类。

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

// 定义一个接口
interface Subject {
    void request();
}

// 实现接口的类
class RealSubject implements Subject {
    @Override
    public void request() {
        System.out.println("Handling real request.");
    }
}

// 代理类的InvocationHandler
class DynamicProxyHandler implements InvocationHandler {
    private Object subject;

    public DynamicProxyHandler(Object subject) {
        this.subject = subject;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("Before method: " + method.getName());
        Object result = method.invoke(subject, args);
        System.out.println("After method: " + method.getName());
        return result;
    }
}

// 客户端代码
public class DynamicProxyDemo {
    public static void main(String[] args) {
        Subject realSubject = new RealSubject();
        InvocationHandler handler = new DynamicProxyHandler(realSubject);

        // 使用Proxy类的newProxyInstance方法创建代理实例
        Subject proxyInstance = (Subject) Proxy.newProxyInstance(
            realSubject.getClass().getClassLoader(),
            realSubject.getClass().getInterfaces(),
            handler
        );

        proxyInstance.request();
    }
}

2. CGLIB动态代理

CGLIB(Code Generation Library)是一个强大的、高性能的代码生成库,它可以扩展Java类和实现接口而无需修改代码。与JDK动态代理不同,CGLIB可以代理没有实现接口的类。

使用CGLIB需要添加额外的依赖,比如通过Maven或Gradle。

<!-- Maven依赖 -->
<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>3.3.0</version>
</dependency>
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

// 没有接口的类
class RealObject {
    public void someMethod() {
        System.out.println("Executing someMethod.");
    }
}

// 代理类的MethodInterceptor
class CglibProxy implements MethodInterceptor {
    private Object target;

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

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

    // 创建代理对象的方法
    public Object getProxyInstance() {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(RealObject.class);
        enhancer.setCallback(this);
        return enhancer.create();
    }
}

// 客户端代码
public class CglibDemo {
    public static void main(String[] args) {
        RealObject realObject = new RealObject();
        CglibProxy proxy = new CglibProxy(realObject);
        RealObject proxyInstance = (RealObject) proxy.getProxyInstance();
        proxyInstance.someMethod();
    }
}

四、总结

代理模式在Java中是一种非常有用的设计模式,它通过引入代理对象来控制对真实对象的访问,从而实现一些非业务功能的添加,如日志记录、权限检查等。静态代理实现简单,但代理类需要手动编写,不便于维护;动态代理则通过反射机制或代码生成技术,在运行时动态地创建代理类,极大地提高了灵活性和可维护性。JDK动态代理和CGLIB动态代理是Java中实现动态代理的两种主要方式,它们各有特点,开发者可以根据具体需求选择合适的实现方式。

在探索代理模式的过程中,我们也提到了“码小课”这个网站,作为一个学习编程的平台,码小课致力于提供高质量的技术文章和教程,帮助开发者们深入理解各种编程概念和技术,希望每一位读者都能在码小课上找到适合自己的学习资源,不断提升自己的技术水平。

推荐文章