java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Java 静态与动态代理

Java代理模式之静态代理与动态代理的区别及优缺点

作者:蜀山剑客李沐白

代理模式是一种常用的设计模式,它允许通过引入一个代理对象来控制对目标对象的访问,在Java中,代理模式被广泛应用,它可以提供额外的功能,如权限检查、缓存、日志记录等,本文将介绍静态代理与动态代理的区别及优缺点,需要的朋友可以参考下

1. 代理模式的定义

代理模式(Proxy Pattern)是指通过代理对象控制对目标对象的访问,并在不改变目标对象的情况下添加额外的功能或控制访问。代理对象和目标对象实现相同的接口,使得客户端可以通过代理对象间接地访问目标对象。

代理模式属于结构型设计模式,它在系统中引入了一个代理对象,该对象代替了客户端直接访问目标对象,从而可以在目标对象的基础上增加一些额外的功能或控制访问。

2. 代理模式的原理

代理模式的核心思想是引入一个代理对象来控制对目标对象的访问。代理对象和目标对象实现相同的接口,使得客户端可以通过代理对象间接地访问目标对象。代理对象负责处理客户端的请求,并在必要时将请求转发给目标对象。在这个过程中,代理对象可以添加额外的逻辑,如权限检查、缓存、日志记录等。

代理模式的主要角色有:

代理模式的工作流程如下:

通过引入代理对象,代理模式可以控制对目标对象的访问,并在不改变目标对象的情况下添加额外的功能或控制访问。

3. 代理模式的实现方式

在Java中,代理模式主要有两种实现方式:静态代理和动态代理。

3.1 静态代理

静态代理是指在编译时就已经确定了代理对象和目标对象的关系,代理类是通过手动编写代码来实现的。在静态代理中,代理类和目标类都实现相同的接口,代理类持有目标对象,并在方法调用前后进行额外的操作。

静态代理的工作原理如下:

静态代理的特点:

静态代理的应用场景:

下面是一个简单的静态代理的示例代码:

// 定义接口
public interface Image {
    void display();
}
// 目标类
public class RealImage implements Image {
    private String filename;
    public RealImage(String filename) {
        this.filename = filename;
        loadFromDisk();
    }
    private void loadFromDisk() {
        System.out.println("Loading image: " + filename);
    }
    @Override
    public void display() {
        System.out.println("Displaying image: " + filename);
    }
}
// 代理类
public class ImageProxy implements Image {
    private String filename;
    private RealImage realImage;
    public ImageProxy(String filename) {
        this.filename = filename;
    }
    @Override
    public void display() {
        if (realImage == null) {
            realImage = new RealImage(filename);
        }
        realImage.display();
    }
}
// 测试类
public class ProxyPatternDemo {
    public static void main(String[] args) {
        // 使用代理对象显示图片
        Image image = new ImageProxy("test.jpg");
        image.display();
        // 图片已加载,直接显示,无需重新加载
        image.display();
    }
}

在上面的示例中,Image 是一个接口,RealImage 是目标类,负责加载和显示图片。ImageProxy 是代理类,通过持有目标类的引用,在需要时创建并使用目标类。ProxyPatternDemo 是一个测试类,用于演示静态代理的使用。

在测试类中,首先创建一个代理对象 ImageProxy,并调用 display() 方法显示图片。代理对象会在第一次调用 display() 方法时,创建真实对象 RealImage 并调用其 display() 方法加载和显示图片。在后续调用 display() 方法时,代理对象直接调用真实对象的 display() 方法,无需重新加载图片。

静态代理的缺点是需要手动编写代理类,工作量较大。如果接口中的方法较多或频繁变动,就需要频繁修改代理类的代码,增加了维护的难度。此外,静态代理的代理类和目标类之间存在紧耦合关系,一旦目标类发生变化,代理类也需要相应修改。

为了解决静态代理的缺点,Java还提供了动态代理机制。

3.2 动态代理

动态代理是指在运行时生成代理对象,而无需手动编写代理类。Java的动态代理机制是基于反射实现的,通过使用java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口来实现动态代理。

在动态代理中,代理类的创建和方法调用都是在运行时完成的。代理对象是在内存中动态创建的,并实现了目标对象的接口,同时持有目标对象的引用。在方法调用时,代理对象通过调用InvocationHandler接口中的方法来处理请求,可以在方法调用前后执行额外的操作。

动态代理的工作原理如下:

动态代理的特点:

动态代理的应用场景:

下面是一个简单的动态代理的示例代码:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
// 定义接口
interface Image {
    void display();
}
// 目标类
class RealImage implements Image {
    private String filename;
    public RealImage(String filename) {
        this.filename = filename;
        loadFromDisk();
    }
    private void loadFromDisk() {
        System.out.println("Loading image: " + filename);
    }
    @Override
    public void display() {
        System.out.println("Displaying image: " + filename);
    }
}
// InvocationHandler 实现类
class ImageInvocationHandler implements InvocationHandler {
    private Object target;
    public ImageInvocationHandler(Object target) {
        this.target = target;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("Before method: " + method.getName());
        Object result = method.invoke(target, args);
        System.out.println("After method: " + method.getName());
        return result;
    }
}
// 测试类
public class ProxyPatternDemo {
    public static void main(String[] args) {
        // 创建目标对象
        Image realImage = new RealImage("test.jpg");
        // 创建 InvocationHandler 实例
        ImageInvocationHandler handler = new ImageInvocationHandler(realImage);
        // 创建代理对象
        Image imageProxy = (Image) Proxy.newProxyInstance(Image.class.getClassLoader(),
                new Class[]{Image.class}, handler);
        // 使用代理对象显示图片
        imageProxy.display();
    }
}

在上面的示例中,Image 是一个接口,RealImage 是目标类,负责加载和显示图片。ImageInvocationHandlerInvocationHandler接口的实现类,用于处理方法调用并执行额外的操作。ProxyPatternDemo 是一个测试类,用于演示动态代理的使用。

在测试类中,首先创建一个目标对象 RealImage,然后创建一个 ImageInvocationHandler 实例,并将目标对象传入构造函数。接下来,通过调用 Proxy 类的 newProxyInstance() 方法来生成代理对象。最后,使用代理对象调用 display() 方法显示图片。

在方法调用时,代理对象会调用 InvocationHandler 接口中的 invoke() 方法处理方法调用。在示例中,我们在 invoke() 方法中实现了打印方法名的额外操作,并通过反射调用目标对象的方法。

以上就是Java代理模式之静态代理与动态代理的区别及优缺点的详细内容,更多关于Java 静态与动态代理的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文