【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 中的进制转换方法。

相关文章
|
5月前
|
Java 数据安全/隐私保护
【面试问题】JDK 动态代理与 CGLIB 区别?
【1月更文挑战第27天】【面试问题】JDK 动态代理与 CGLIB 区别?
|
5月前
|
设计模式 安全 Java
静态代理还是动态代理?来聊聊Java中的代理设计模式
代理模式(Proxy Design Pattern)是一种结构型设计模式,为一个对象提供一个代理对象,然后使用代理对象控制对原对象的引用。即通过代理对象访问目标对象。被代理的对象可以是远程对象、创建开销大的对象或需要安全控制的对象。
44 0
静态代理还是动态代理?来聊聊Java中的代理设计模式
|
5月前
|
Java 开发者 Spring
什么是静态代理和动态代理,两者的区别(笔记)
什么是静态代理和动态代理,两者的区别(笔记)
191 0
|
缓存 Java 测试技术
动态代理:JDK动态代理源码学习
动态代理:JDK动态代理源码学习
58 1
|
设计模式 Java 数据安全/隐私保护
剖析代理模式及Java两种动态代理(JDK动态代理和CGLIB动态代理)
本文详述了代理模式以及我们经常接触到的两种具体实现(JDK动态代理和CGLIB动态代理),为读者理解代理模式、JDK动态代理和CGLIB动态代理提供帮助
183 0
剖析代理模式及Java两种动态代理(JDK动态代理和CGLIB动态代理)
|
设计模式 安全 Java
面试篇之什么是静态代理?什么是动态代理?
Java中的代理,开源理解为通过代理去访问实际的目标对象,比如呢?我们平常买卖二手车的中间商,就可以看作一个代理类,不过你也可以直接去和二手车的主人买卖。
132 0
|
Java Spring
动态代理学习(二)JDK动态代理源码分析
动态代理学习(二)JDK动态代理源码分析
78 0
动态代理学习(二)JDK动态代理源码分析
|
Java API 数据库
Java 结合实例学会使用 静态代理、JDK动态代理、CGLIB动态代理
Java 结合实例学会使用 静态代理、JDK动态代理、CGLIB动态代理
114 0
Java 结合实例学会使用 静态代理、JDK动态代理、CGLIB动态代理
java178-终篇?静态代理?动态代理?
java178-终篇?静态代理?动态代理?
73 0