Detailed explanation of Java proxy mode, the difference and advantages and disadvantages of static proxy and dynamic proxy

The proxy pattern is a commonly used design pattern that allows access to a target object to be controlled by introducing a proxy object. In Java, the proxy pattern is widely used, which can provide additional functions, such as permission checking, caching, logging, etc., and can be extended without modifying the target object.

1. Definition of proxy mode

Proxy Pattern refers to controlling access to the target object through the proxy object, and adding additional functions or controlling access without changing the target object. The proxy object and the target object implement the same interface, so that the client can indirectly access the target object through the proxy object.

The proxy mode belongs to the structural design mode, which introduces a proxy object in the system, which replaces the client's direct access to the target object, so that some additional functions or access control can be added on the basis of the target object.

2. The principle of proxy mode

The core idea of ​​the proxy pattern is to introduce a proxy object to control access to the target object. The proxy object and the target object implement the same interface, so that the client can indirectly access the target object through the proxy object. The proxy object is responsible for processing the client's request and, if necessary, forwarding the request to the target object. During this process, the proxy object can add additional logic, such as permission checking, caching, logging, etc.

The main roles of the proxy mode are:

  • Abstract subject (Subject): defines the common interface of the proxy object and the target object, usually an interface or abstract class in Java.
  • Target object (RealSubject): defines the real object represented by the proxy object, and is the specific executor of business logic.
  • Proxy object (Proxy): holds a reference to the target object, and implements the same interface as the target object, and performs additional operations before and after the method call.

The workflow of proxy mode is as follows:

  1. The client sends a request to the proxy object.
  2. After the proxy object receives the request, it can perform some additional logic before or after the request is forwarded to the target object.
  3. The proxy object forwards the request to the target object.
  4. The target object executes specific business logic and returns the result.
  5. The proxy object can perform some additional operations before or after the target object returns the result.
  6. The proxy object returns the result to the client.

By introducing a proxy object, the proxy pattern can control access to the target object and add additional functionality or control access without changing the target object.

3. Implementation of proxy mode

In Java, there are two main implementations of proxy mode: static proxy and dynamic proxy.

3.1 Static proxy

Static proxy means that the relationship between the proxy object and the target object has been determined at compile time, and the proxy class is implemented by manually writing code. In a static proxy, both the proxy class and the target class implement the same interface, the proxy class holds the target object, and performs additional operations before and after method calls.

Static proxies work as follows:

  1. Define an interface (or abstract class) as the target interface, and the target object implements this interface.
  2. Create a proxy class that implements the target interface and holds a reference to the target object.
  3. Override the method of the target interface in the proxy class, and perform the required additional operations before and after the method call.
  4. Clients use proxy objects to access target objects.

Features of static proxy:

  • It is necessary to manually write the proxy class, and the workload is relatively large.
  • The target object must implement the interface.
  • The relationship between the proxy class and the target class is determined at compile time and cannot be changed dynamically.

Application scenarios of static proxy:

  • Security control: Proxy classes can perform security controls such as permission checks before calling the target method.
  • Remote call: The proxy class can encapsulate the details related to network communication, making calling remote methods as simple as calling local methods.
  • Performance monitoring: The proxy class can collect information such as the execution time and number of calls of the method for performance monitoring and statistical analysis.

The following is a sample code for a simple static proxy:

// 定义接口
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();
    }
}

In the above example, Imageit is an interface, RealImagewhich is the target class, which is responsible for loading and displaying pictures. ImageProxyIt is a proxy class that creates and uses the target class when needed by holding a reference to the target class. ProxyPatternDemoIs a test class used to demonstrate the use of static proxies.

In the test class, first create a proxy object ImageProxy, and call display()the method to display the picture. display()The proxy object will create a real object RealImageand call its display()method to load and display the picture when the method is called for the first time . When the method is called subsequently display(), the proxy object directly calls display()the method of the real object without reloading the image.

The disadvantage of the static proxy is that the proxy class needs to be manually written, and the workload is relatively large. If there are many methods in the interface or frequent changes, it is necessary to frequently modify the code of the proxy class, which increases the difficulty of maintenance. In addition, there is a tight coupling relationship between the proxy class and the target class of the static proxy. Once the target class changes, the proxy class also needs to be modified accordingly.

In order to solve the shortcomings of static proxy, Java also provides a dynamic proxy mechanism.

3.2 Dynamic proxy

Dynamic proxy refers to generating proxy objects at runtime without manually writing proxy classes. Java's dynamic proxy mechanism is implemented based on reflection, and dynamic proxy is realized by using java.lang.reflect.Proxyclasses and interfaces.java.lang.reflect.InvocationHandler

In dynamic proxies, the creation of proxy classes and method invocations are done at runtime. The proxy object is dynamically created in memory, and implements the interface of the target object, while holding the reference of the target object. When the method is called, the proxy object InvocationHandlerprocesses the request by calling the method in the interface, and can perform additional operations before and after the method call.

Dynamic proxies work as follows:

  1. Define an interface as the target interface.
  2. Create an InvocationHandlerimplementation class of the interface that is responsible for handling method calls and performing additional operations.
  3. Use Proxythe static method of the class newProxyInstance()to generate a proxy object while specifying the target object and InvocationHandler.
  4. The client uses the proxy object to access the methods of the target object.

Features of dynamic proxy:

  • There is no need to manually write proxy classes, and proxy objects are dynamically generated at runtime.
  • The target object does not need to implement the interface, but only needs to define the common interface of the target object.
  • The relationship between the proxy object and the target object is determined at runtime and can be changed dynamically.

Application scenarios of dynamic proxy:

  • AOP (Aspect-Oriented Programming): Dynamic proxies can perform additional operations before and after the execution of the target method, such as permission checking, transaction management, etc. It is a common way to implement AOP.
  • Lazy loading: The dynamic proxy can be loaded and initialized when the target method is called to achieve the effect of lazy loading.
  • Logging: The dynamic proxy can record log information before and after the execution of the target method.

Here is a sample code for a simple dynamic proxy:

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();
    }
}

In the above example, Imageit is an interface, RealImagewhich is the target class, which is responsible for loading and displaying pictures. ImageInvocationHandlerIs InvocationHandlerthe implementation class of the interface, which is used to handle method calls and perform additional operations. ProxyPatternDemois a test class that demonstrates the use of dynamic proxies.

In the test class, first create a target object RealImage, then create an ImageInvocationHandlerinstance, and pass the target object into the constructor. Next, generate the proxy object by calling the method Proxyof the class newProxyInstance(). Finally, use the proxy object to call display()the method to display the picture.

When the method is called, the proxy object will call the method InvocationHandlerin the interface invoke()to handle the method call. In the example, we invoke()implement the extra operation of printing the method name in the method, and call the method of the target object through reflection.

Guess you like

Origin blog.csdn.net/u012581020/article/details/131396583