Introduction to proxy mode

Concept :

Proxy Pattern is a structural design pattern that allows controlling access to original objects by creating a proxy object. The proxy object acts as an intermediary between the client and the target object and can add additional functionality or restrict access without changing the target object.

Features :

  1. The proxy pattern hides the real objects by introducing proxy classes and provides the same interface as the real objects, so that the client does not need to interact directly with the real objects.
  2. Proxy classes can perform additional operations before or after calling the real object, such as permission verification, caching, etc.
  3. The client cannot tell whether a proxy is used or not because they both follow the same interface.

Advantages :

  1. Reduce system coupling: Decouple the client and the target object to reduce direct dependence on the target class.
  2. Improve security: permission verification and access control through proxies.
  3. Enhanced scalability: New features can be added without modifying the source code.

Disadvantages :

  1. Increased complexity: An additional layer of indirection is introduced, which may increase code complexity in some simple scenarios.
  2. For some methods that involve frequent calls, performance is reduced due to the need for multiple forwardings.

Applicable scenarios :

  1. Remote proxy: used to access objects in different address spaces, such as remote method invocation (RPC).
  2. Virtual Agent: Used to load large objects on demand or delay the creation of expensive objects to improve system performance.
  3. Security proxy: Used to control access to sensitive resources.
  4. Smart reference proxy: used to add additional operations such as caching, logging, etc.

Implementation method :

static proxy

Implementation principle:

The proxy class and the specific proxy class have been determined at compile time, and a specific implementation class is directly defined in the code as the target object and a corresponding specific implementation class as the proxy object. Static proxies require manually writing the forwarding logic for each method and can only operate on specific types.

Implementation code:

// 目标接口
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);
    }
}

// 代理类
class ImageProxy implements Image {
    private String filename;
    private RealImage realImage;

    public ImageProxy(String filename) {
        this.filename = filename;
        this.realImage = null; // 初始时不加载真实对象
    }

    @Override
    public void display() {
        if (realImage == null) { // 懒加载,只有在需要时才创建真实对象
            realImage = new RealImage(filename);
        }
        realImage.display();
    }
}

public class Main {

    public static void main(String[] args) {

        Image image1 = new ImageProxy("image1.jpg");//无输出
        // 使用代理显示图片,只有在调用 `display()` 方法时才会加载真实图片对象
        image1.display();//输出 Loading image: image1.jpg
                         //    Displaying image: image1.jpg

        
        Image image2 = new RealImage("image2.jpg");//输出Loading image: image2.jpg
        // 直接使用目标类显示图片,立即加载真实图片对象并显示
        image2.display();//输出 Displaying image: image2.jpg
    }
}

 In the above example, we defined a target interface  Image and its concrete implementation class  RealImage.  ImagProxThen a proxy class y is created to control access to the target object. When the client creates a proxy class object, the image will not be loaded immediately. The image will be loaded and displayed only when display() is called. When the target object is created, the image is loaded immediately.

Dynamic proxy :

Dynamic proxy refers to the process of dynamically generating proxy classes at runtime. It does not require manual writing of specific proxy classes. Instead, it creates a new proxy class in memory through Java 's reflection mechanism and bytecode generation technology, and The runtime forwards method calls to the real object.

Implementation principle:

  1. Define the target interface: First, you need to define a target interface, that is, the interface followed by the proxy object.
  2. Implement the InvocationHandler interface: Create a class that implements  the java.lang.reflect.InvocationHandler  interface. This class is responsible for handling all method calls and performing corresponding operations.
  3. Create a Proxy object: Use  the static method newProxyInstance() of the java.lang.reflect.Proxy class  to create a proxy object. This method returns a new object that implements the target interface and is called by the specified InvocationHandler processing method.  

Implementation code :

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 invocation");
        Object result = method.invoke(target, args);
        System.out.println("After method invocation");
        return result;
    }
}

public class Main {

    public static void main(String[] args) {

        RealImage realImage = new RealImage("image.jpg");

        // 创建代理对象并绑定目标对象和 InvocationHandler 对象
        Image proxyImage = (Image) Proxy.newProxyInstance(
                realImage.getClass().getClassLoader(),
                realImage.getClass().getInterfaces(),
                new ImageInvocationHandler(realImage)
        );

        // 通过代理对象调用方法,实际上会转发给真实对象的相应方法,并在前后执行额外操作
        proxyImage.display();
    }
}

In the above example, we defined a target interface  Image and its concrete implementation class  RealImag e . Then a class  ImagInvocatioHandler that implements  the java.lang.reflect.InvocationHandler interface is created to handle all method calls. Finally, use the static method  newProxInstance()  of  the java.lang.reflect.Prox y class to create a proxy object and bind the target object and the InvocationHandler object together. When the client calls a method through the proxy object, it is actually forwarded to the corresponding method of the real object, and additional operations are performed before and after. Java 's reflection mechanism and bytecode generation technology are used to dynamically create proxy classes at runtime.

There is a problem:

  1. Dynamic proxies can only operate on interfaces and cannot directly operate on ordinary classes.
  2. Since the method call must be handled through reflection every time, there may be some loss in performance.

Guess you like

Origin blog.csdn.net/aidscooler/article/details/132752875
Recommended