Java proxy mode

1. Principle of agent mode

Wrap the object with a proxy object and replace the original object with the proxy object. Any call to the original object must be called through the proxy object. The proxy object determines whether and when method calls are transferred to the original object.

2. Static proxy mode

Here is an example of a clothing factory to illustrate the static agent mode:
The proxy class and the proxy class need to jointly implement an interface (specification), which contains core functions. The proxy class needs to have a private member of the same type as the interface. The proxy class only needs to complete all core functions, and the core functions of the proxy class can add other methods to assist the core functions. The implementation of the real core functions is still to call the core functions of the proxy class.

package com.zju.proxy;

// The interface that the proxy class and the proxy class need to implement together
interface ClothFactory {
	// Define core functions in the interface
    void produceCloth();
}

// proxy class
class ProxyClothFactory implements ClothFactory {
    // At that time, the proxy object needs to be assigned
    private ClothFactory factory;

    public ProxyClothFactory(ClothFactory factory) {
        this.factory = factory;
    }

    @Override
    public void produceCloth() {
        System.out.println("Do some preparatory work for the agent factory...");
        // The real core function is still performed by the proxy class
        factory.produceCloth();
        System.out.println("Agent the factory to do some finishing work...");
    }
}

// Proxy class
class NikeClothFactory implements ClothFactory {

    @Override
    public void produceCloth() {
        System.out.println("Nike The factory produces a batch of sportswear...");
    }
}

public class StaticProxyTest {
    // Test agent
    public static void main(String[] args) {
        ClothFactory factory = new ProxyClothFactory(new NikeClothFactory());
        factory.produceCloth();
    }
}

The operation result is:

Do some preparatory work for the agent factory...
Nike The factory produces a batch of sportswear...
Agent the factory to do some finishing work...

Process finished with exit code 0

The characteristic of static proxy mode is that the classes of proxy classes and target objects are determined during compilation, which is not conducive to program expansion. At the same time, each agent class can only serve one interface, so there must be too many agents in program development. It is best to complete all proxy functions through a proxy class.

3. Dynamic agent mode

Dynamic proxy refers to the method that the client calls other objects through the proxy class, and it is the proxy object that dynamically creates the target class as needed during the program running.

The usage of dynamic agent: debugging and remote method call.

Dynamic proxy requirements: the interface (specification) and proxy class are defined before compilation, and the proxy class is generated during operation.

Advantages of dynamic agents over static agents:
All methods declared in the abstract role (Interface) are transferred to a centralized method of the calling processor, so that we can deal with many methods more flexibly and uniformly.

Problems to be solved to implement dynamic agent:
Question 1: how to dynamically create a proxy class and its object according to the proxy class loaded into memory?
Question 2: when a method is called through the object of the proxy class, how to dynamically call the method with the same name in the proxy class?

The comments in the code are written in detail, so there is no specific description:

package com.zju.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

interface Human {
    String getBelief();

    void eat(String food);
}

// Proxy class
class SuperMan implements Human {

    @Override
    public String getBelief() {
        return "I believe I can fly!";
    }

    @Override
    public void eat(String food) {
        System.out.println("I love eating" + food);
    }
}

// To solve problem 1: dynamically create a proxy class and its object according to the proxy class loaded into memory
class ProxyFactory {

    // Tool class: privatize the construction method to prevent instantiation
    private ProxyFactory() {}

    /**
     * Call this method to return an object of a proxy class
     * @param obj Object of the proxied class
     * @return Type of proxy class
     */
    public static Object getProxyInstance(Object obj) {
        Class clazz = obj.getClass();
        MyInvocationHandler handler = new MyInvocationHandler();

        // Pass the proxied class to the handler
        handler.bind(obj);

        // Automatically generate a proxy class that implements the same interface as the proxy class, and the handler is used to write the method of the proxy class
        return Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), handler);
    }
}

// For problem 2: when a method is called through the object of the proxy class, it dynamically calls the method with the same name in the proxy class
class MyInvocationHandler implements InvocationHandler {

    // obj is the proxy object passed in from the proxy object
    private Object obj;

    /**
     * Bind incoming proxied object
     * @param obj Proxied object
     */
    public void bind(Object obj) {
        this.obj = obj;
    }

    /**
     * When we call method f through the object of the proxy class, the following method invoke() will be called automatically
     * The function of the method f to be executed by the proxy class is declared in invoke()
     * @param proxy Object of proxy class
     * @param method The method f method object called by the object of the proxy class is also used as the method to be called by the object of the proxy class
     * @param args Parameter list of method f
     * @return Return value of method f
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        System.out.println("The proxy class starts processing before the execution of the core method...");

        // Executes the core methods of the proxied class
        Object returnValue = method.invoke(obj, args);

        System.out.println("The proxy class starts processing after the execution of the core method...");

        return returnValue;
    }
}

public class ProxyTest {

    // Test agent
    public static void main(String[] args) {
        // Case 1
        // At this time, proxyInstance is the object of proxy class
        Human proxyHuman = (Human) ProxyFactory.getProxyInstance(new SuperMan());

        // When a method is called through a proxy class object, it will automatically call the method with the same name in the proxy class
        String belief = proxyHuman.getBelief();
        System.out.println(belief);

        // When a method is called through a proxy class object, it will automatically call the method with the same name in the proxy class
        proxyHuman.eat("Sichuan Mala");

        System.out.println("------ branch - Septum - symbol -------");

        // Case 2
        // At this time, proxyInstance is the object of proxy class
        ClothFactory proxyClothFactory = (ClothFactory) ProxyFactory.getProxyInstance(new NikeClothFactory());
        // When a method is called through a proxy class object, it will automatically call the method with the same name in the proxy class
        proxyClothFactory.produceCloth();
    }
}

The operation result is:

The proxy class starts processing before the execution of the core method...
The proxy class starts processing after the execution of the core method...
I believe I can fly!
The proxy class starts processing before the execution of the core method...
I like Sichuan spicy hot
 The proxy class starts processing after the execution of the core method...
------ branch - Septum - symbol -------
The proxy class starts processing before the execution of the core method...
Nike The factory produces a batch of sportswear...
The proxy class starts processing after the execution of the core method...

Process finished with exit code 0

Keywords: Java JavaEE Design Pattern Dynamic Proxy

Added by jgires on Sat, 20 Nov 2021 08:28:13 +0200