【JavaSE专栏24】静态代理和动态代理,到底代理了啥?

简介: 【JavaSE专栏24】静态代理和动态代理,到底代理了啥?

本文对 Java 的静态代理和动态代理进行了介绍,讲解了代理模式的基本原理,并给出了样例代码。

一、Java 代理模式

Java 代理模式是一种结构型设计模式,它允许通过创建一个中间类(代理类)来控制对其他对象的访问。

代理模式可以为目标对象提供额外的功能保护目标对象免受直接访问

以下是一个简单的 Java 代码示例,演示了静态代理模式的实现。

  1. 定义一个接口
interface Image {
    void display();
}
  1. 创建目标类(被代理类)
class RealImage implements Image {
    private String filename;
    public RealImage(String filename) {
        this.filename = filename;
        loadFromDisk();
    }
    private void loadFromDisk() {
        System.out.println("Loading image: " + filename);
    }
    public void display() {
        System.out.println("Displaying image: " + filename);
    }
}
  1. 创建代理类
class ProxyImage implements Image {
    private RealImage realImage;
    private String filename;
    public ProxyImage(String filename) {
        this.filename = filename;
    }
    public void display() {
        if (realImage == null) {
            realImage = new RealImage(filename);
        }
        realImage.display();
    }
}
  1. 使用代理类和目标类
public class Main {
    public static void main(String[] args) {
        Image image = new ProxyImage("example.jpg");
        // 图像将从磁盘加载
        image.display();
        // 图像不再从磁盘加载
        image.display();
    }
}

在上述示例中,RealImage 是目标类,负责加载和显示图像。ProxyImage 是代理类,控制对 RealImage 的访问。当第一次调用 display() 方法时,代理类会创建一个真实图像对象,并调用它的 display() 方法。在后续调用中,代理类直接调用真实图像对象的 display() 方法,而无需再次加载图像,这样可以提高性能并延迟真正的对象创建。


二、Java 静态代理

Java静态代理是一种代理模式的实现方式,它通过创建一个代理类来控制对目标对象的访问,在静态代理中,代理类和目标类都必须事先定义好,并且代理类需要实现与目标类相同的接口。

在静态代理中,代理类充当了目标类的外壳,用户通过代理类间接访问目标类,并且可以在代理类中添加额外的逻辑,如日志记录、性能统计等。代理类负责将请求传递给目标类,并在调用前后执行一些预处理和后处理操作。

通过使用静态代理,可以在不修改目标类的情况下扩展其功能或添加额外的行为,同时也方便对目标类的访问进行控制,提高代码的可维护性和灵活性。

需要注意的是,静态代理模式生成的每个代理类只能代理一个具体的目标类,如果有多个目标类需要代理,就需要为每个目标类创建一个对应的代理类。这种方式可能导致代理类过多的问题,因此在一些场景下,动态代理可能更加方便和灵活。

在第一章中讲解的 RealImage 样例,就是静态代理,接下来再举一个例子,巩固同学们对静态代理的印象。

  1. 定义一个接口
interface Subject {
    void request();
}
  1. 创建目标类(被代理类)
class RealSubject implements Subject {
    public void request() {
        System.out.println("RealSubject: Handling the request.");
    }
}
  1. 创建代理类
class ProxySubject implements Subject {
    private RealSubject realSubject;
    public ProxySubject(RealSubject realSubject) {
        this.realSubject = realSubject;
    }
    public void request() {
        System.out.println("ProxySubject: Pre-processing the request.");
        realSubject.request();
        System.out.println("ProxySubject: Post-processing the request.");
    }
}
  1. 使用代理类和目标类
public class Main {
    public static void main(String[] args) {
        RealSubject realSubject = new RealSubject();
        ProxySubject proxySubject = new ProxySubject(realSubject);
        // 通过代理类调用目标类的方法
        proxySubject.request();
    }
}

在上述示例中,RealSubject 是目标类,负责处理请求。ProxySubject 是代理类,用于在目标类的方法调用前后进行预处理和后处理

当通过代理类调用 request() 方法时,代理类会先执行一些额外的操作(在本例中是打印一些消息),然后再调用真实主题对象的 request() 方法。最后,代理类可以再次执行其他操作(在本例中也是打印一些消息),这样就实现了对目标类方法调用的控制和扩展

注意:以上是静态代理模式的简单示例,实际使用时,可能会有更多的接口方法和参数。


三、Java动态代理

Java动态代理是一种在运行时动态生成代理类的机制,用于代理其他对象的访问

与静态代理不同,动态代理无需事先定义代理类,而是在程序运行时根据指定的接口和处理器生成代理类

在动态代理中,代理类并不是自己实现目标接口的方法,而是通过委托给一个 InvocationHandler(调用处理器)来处理对目标类方法的调用。InvocationHandler 接收到方法调用后,可以在调用前后执行自定义的逻辑。动态代理通过反射机制在运行时动态生成代理类,并将方法调用传递到 InvocationHandler 进行处理。

使用动态代理可以避免为每个目标类编写具体的代理类,提高代码的灵活性和可维护性。它可以在运行时根据需要动态地生成代理类,适用于代理多个目标类的情况。

Java 中提供了一个 java.lang.reflect.Proxy 类,用于创建动态代理对象。该类提供了一个静态方法 newProxyInstance(),通过指定目标类的加载器、目标类实现的接口、以及一个 InvocationHandler 来创建代理对象。

总的来说,Java 动态代理是一种在运行时动态生成代理类的机制,通过委托给 InvocationHandler 处理方法调用,实现对目标对象的代理。它是一种强大且灵活的代理方式,可以用于各种场景中需要动态创建代理类的情况。

以下是一个使用 Java 动态代理的简单示例代码。

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
// 定义一个接口
interface Subject {
    void request();
}
// 创建目标类(被代理类)
class RealSubject implements Subject {
    public void request() {
        System.out.println("RealSubject: Handling the request.");
    }
}
// 创建动态代理处理器
class DynamicProxyHandler implements InvocationHandler {
    private Object target;
    public DynamicProxyHandler(Object target) {
        this.target = target;
    }
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("DynamicProxy: Pre-processing the request.");
        Object result = method.invoke(target, args);
        System.out.println("DynamicProxy: Post-processing the request.");
        return result;
    }
}
// 使用代理类和目标类
public class Main {
    public static void main(String[] args) {
        RealSubject realSubject = new RealSubject();
        // 创建动态代理实例
        Subject proxySubject = (Subject) Proxy.newProxyInstance(
                realSubject.getClass().getClassLoader(),
                realSubject.getClass().getInterfaces(),
                new DynamicProxyHandler(realSubject)
        );
        // 通过代理类调用目标类的方法
        proxySubject.request();
    }
}

在上述示例中,RealSubject 是目标类,负责处理请求。DynamicProxyHandler 是动态代理处理器,实现了 InvocationHandler 接口,并负责在目标方法调用前后进行预处理和后处理。

在 Main 类中,首先创建了一个 RealSubject 的实例。然后使用 Proxy.newProxyInstance() 方法创建动态代理实例,该方法接受三个参数:类加载器目标类实现的接口数组以及动态代理处理器。通过调用动态代理实例的方法,实际上会调用到 DynamicProxyHandlerinvoke() 方法,在其中执行了额外的操作,然后再调用目标对象的对应方法。

使用动态代理,可以避免为每个目标类都创建一个对应的代理类,而是在运行时生成代理类,从而更加灵活地控制和扩展目标类的行为


四、总结

本文对 Java 中的静态代理和动态代理进行了介绍,讲解了代理模式的基本原理,并给出了样例代码。在下一篇博客中,将讲解 Java 中的进制转换方法。

相关文章
|
JavaScript 前端开发 数据处理
【Vue面试题二十八】、vue要做权限管理该怎么做?如果控制到按钮级别的权限怎么做?
这篇文章讨论了Vue中实现权限管理的策略,包括接口权限、路由权限、菜单权限和按钮权限的控制方法,并提供了不同的实现方案及代码示例,以确保用户只能访问被授权的资源。
【Vue面试题二十八】、vue要做权限管理该怎么做?如果控制到按钮级别的权限怎么做?
|
存储 算法 搜索推荐
深度优先遍历与广度优先遍历:理解它们的原理与差异
深度优先遍历与广度优先遍历:理解它们的原理与差异
|
API Nacos
【想进大厂还不会阅读源码】ShenYu源码-重构同步数据服务
ShenYu源码阅读📚。我们看下PR的标题和Concersation的头一句,大概意思就是重构注册中心数据同步到ShenYu网关的方式。大家看看重构了有没好处呢?不仅获得了知识,还获得了一次开源贡献,何乐而不为呢
150 3
Application provided invalid, non monotonically increasing dts to muxer in stream
Application provided invalid, non monotonically increasing dts to muxer in stream
859 0
Application provided invalid, non monotonically increasing dts to muxer in stream
|
弹性计算 负载均衡 Kubernetes
人人租机上云案例
我们是线上租赁,面临高成本高流失等问题,阿里小程序为我们赋能
1910 85
|
安全 物联网 API
AliOS Things组件功能介绍(三)
AliOS Things组件功能介绍(三)
407 0
|
存储 监控 对象存储
阿里云OSS预留空间是什么?
阿里云OSS预留空间是什么?对象存储OSS预留空间是什么?预留空间是指定地域的,仅可抵扣该地域“标准存储 - 本地冗余”的OSS存储费用,不支持非存储容量费用抵扣,付费周期一年,阿里云对象存储推出全新预留空间产品(Reserved Capacity),客户购买一年的预留空间,较按量付费,最高可节省70%的费用。还有无地域属性预留空间
1179 0
|
消息中间件 SQL 分布式计算
Spark分布式计算框架之SparkStreaming+kafka
Spark分布式计算框架之SparkStreaming+kafka
238 0
|
人工智能 Java 开发工具
VB编程:IF语句嵌套实例猜数小游戏
VB编程:IF语句嵌套实例猜数小游戏
273 0