作者主页:Designer 小郑 作者简介:Java全栈软件工程师一枚,欧博官网来自浙江宁波,负责开发管理公司OA项目,专注软件前后端开发(Vue、SpringBoot和微信小程序)、系统定制、远程技术指导。CSDN学院、蓝桥云课认证讲师,全栈领域优质创作者。热爱技术、专注业务、开放合作、乐于分享,期待你我共同成长! 主打方向:Vue、SpringBoot、微信小程序 本文对 Java 的静态代理和动态代理进行了介绍,讲解了代理模式的基本原理,并给出了样例代码。 一、Java 代理模式Java 代理模式是一种结构型设计模式,它允许通过创建一个中间类(代理类)来控制对其他对象的访问。 代理模式可以为目标对象提供额外的功能或保护目标对象免受直接访问。 以下是一个简单的 Java 代码示例,演示了静态代理模式的实现。 定义一个接口 代码语言:javascript 复制 interface Image { void display(); } 创建目标类(被代理类) 代码语言:javascript 复制 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); } } 创建代理类 代码语言:javascript 复制 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(); } } 使用代理类和目标类 代码语言:javascript 复制 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 样例,就是静态代理,接下来再举一个例子,巩固同学们对静态代理的印象。 定义一个接口 代码语言:javascript 复制 interface Subject { void request(); } 创建目标类(被代理类) 代码语言:javascript 复制 class RealSubject implements Subject { public void request() { System.out.println("RealSubject: Handling the request."); } } 创建代理类 代码语言:javascript 复制 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."); } } 使用代理类和目标类 代码语言:javascript 复制 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 动态代理的简单示例代码。 代码语言:javascript 复制 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() 方法创建动态代理实例,该方法接受三个参数:类加载器、目标类实现的接口数组以及动态代理处理器。通过调用动态代理实例的方法,实际上会调用到 DynamicProxyHandler 的 invoke() 方法,在其中执行了额外的操作,然后再调用目标对象的对应方法。 使用动态代理,可以避免为每个目标类都创建一个对应的代理类,而是在运行时生成代理类,从而更加灵活地控制和扩展目标类的行为。 在这里插入图片描述 (责任编辑:) |