JAVA design pattern proxy pattern

Posted by glodders on Mon, 28 Feb 2022 20:21:09 +0100

summary

Proxy mode: first, there must be an interface. Both proxy class and proxy class implement the same interface. Finally, the proxy is the method of the proxy class.

Proxy pattern is a design pattern that is widely used in Java development.
Agent design is to provide an agent for an object to control access to the object. Any call to the original object must pass through the proxy. The proxy object decides whether and when to transfer the method call to the original object, that is, the proxy class method is the encapsulation of the proxy class method.

Static proxy

Statically define proxy classes: proxy classes and proxied classes can be determined during compilation.
Limitations: it is not conducive to the expansion of the program. Each agent class can only serve one interface. In this way, there must be too many agents in program development.
It is best to use a proxy class to complete the proxy function of all interfaces of the same type.

Creation steps of proxy class:
Declare the attribute of an interface type;
Define the constructor (interface type parameter), and pass in the proxy class object when creating the object, which is used to call the method of the proxy class;
Implement the interface method.

give an example:

// Interface service
public interface Network {
	public void browse();
}
// Proxy class
class RealServer implements Network { 
	@Override
	public void browse() {
		System.out.println("Real server browsing information");
} }
// proxy class
class ProxyServer implements Network {
	// Declare a property of an interface type
	private Network network;
	// When initializing, the constructor passes in the proxied class, which is used to call the methods of the proxied class
	public ProxyServer(Network network) {
		this.network = network; }
	public void check() {
		System.out.println("Check network connection and other operations");
	}
	public void browse() {
		check();
		network.browse();
	} }
// test
public class ProxyDemo {
	public static void main(String[] args) {
		// Create a proxy class object and pass in the proxy class object
		Network net = new ProxyServer(new RealServer());
		// Methods for accessing proxy class objects
		net.browse();
} }

Dynamic agent

Dynamically generate proxy classes.
The JDK's own dynamic agent dynamically creates an agent class at runtime, so that the agent class and the proxy class implement the same interface.
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 when the program runs.

A Proxy class and an invocationhandler interface are required:
java.lang.reflect.Proxy: the operation class that is dedicated to proxy. It is the parent class of all dynamic proxy classes. This class dynamically generates proxy classes for one or more interfaces.

Three problems need to be solved to realize dynamic agent:
1 how to dynamically create a proxy class and its object according to the proxy class loaded into memory and its implemented interface?
Call proxy Newproxyinstance (you can use the class loader of the proxy class, the interface implemented by the proxy class, and the anonymous inner class of the InvokationHandler interface) to create proxy class objects using reflection.
Define a getProxyInstance(Object obj) method to return the proxy class object.

2 how to dynamically call the method with the same name of the proxy class when calling the method through the proxy class object?
It is implemented through the invocationhandler interface.
When a proxy class object invokes a method, it can dynamically call the method with the same name of the proxy class (implemented by invokationhandler). All methods declared by the interface are transferred to a centralized method of the invokationhandler, which can handle many methods more flexibly and uniformly.

3. When invoking according to the invoke method of invokationHandler, all the methods of the proxy class are processed according to the same process, so how to customize and extend the methods of different proxy classes? And different methods of the same proxy class?
Proxy can only be provided for interface types with similar functions.
You can define the general methods added by dynamic agents (extension methods applicable to each dynamic method), and then call them dynamically. Refer to section oriented programming.
Write a tool class Utils that defines the general method of the proxy class, which is used as the pre-processing and post-processing process of the proxy method in the proxy method.

The implementation of dynamic proxy requires interfaces and proxied class objects, which are created in advance.
When obtaining the object in the test class, you need to first forcibly convert the type to the interface type.
Question: if a proxy class implements multiple interfaces? Can the generated proxy class be declared as each interface type- yes

give an example:

//Common interface (multiple interfaces) first
public interface Interface1 {
    void interfacetest1();
}
public interface Interface2 {
    void interfacetest2();
}
//Then there is the proxy class, which implements multiple interfaces
public class Interface1Impl implements Interface1,Interface2 {
    @Override
    public void interfacetest1() {
        System.out.println("Execute the proxy class method: interfacetest1!");
    }

    @Override
    public void interfacetest2() {
        System.out.println("Execute the proxy class method: interfacetest2!");
    }
}
//Then write the general method class added in the dynamic proxy method
public class ProxyMethodUtils {
    public static void preProcess(){
        System.out.println("Agent class preprocessing method");
    }
    public static void postProcess(){
        System.out.println("Post processing method of agent class");
    }
}
//Dynamic proxy class
public class ProxyFactory1 {

    /**
     * @param object object Is a proxied class object
     * @return
     */
    public static Object getProxyInstance(Object object){
    	//By the interface object getClass(). Getinterfaces(), implemented by proxy class object and InvocationHandler, dynamically creates proxy classes
		//InvokationHandler in newProxyInstance uses anonymous implementation class
        return Proxy.newProxyInstance(object.getClass().getClassLoader(),
                object.getClass().getInterfaces(), 
                The interface can be obtained by reflection proxy Call with the same name method(Method type) And the parameters passed into the method
                new InvocationHandler() {
                //The invoke method defines the processing flow of dynamically calling the proxy class method. Proxy is the object of proxy class
               
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    	//Pretreatment
                        ProxyMethodUtils.preProcess();
                        //Call the method of the proxied class obtained through reflection
                        Object retval = method.invoke(object,args);
                        System.out.println("Returned value of proxy method:" + retval);
                        //Post processing
                        ProxyMethodUtils.postProcess();
                        return retval;
                    }
                });
    }
}

public class ProxyTest {
    public static void main(String[] args) {
        //Proxied class object
        Interface1Impl interface1 = new Interface1Impl();

        //Create a proxy class and declare it as Interface1 interface type (one of the two interfaces implemented by the proxy class)
        Interface1 proxy1Interface1 = (Interface1) ProxyFactory1.getProxyInstance(interface1);
        
        proxy1Interface1.interfacetest1();
    }
}

Referring to the following aspect oriented programming, you can define the general method added by the dynamic agent (the extension method applicable to each dynamic method), and then call it dynamically.

AOP aspect oriented programming: extract the general method as the aspect of the real proxy method, and then realize the aspect method (proxy method), which is aspect oriented programming.
The AOP proxy contains all the methods of the target object.
However, there are differences between the methods in AOP proxy and the methods of target object: the methods in AOP proxy can insert some general processing before and after executing the target method.

Reflection related knowledge

Class is the root of Reflection. All loaded structures in a class can be completely obtained through class. For any class you want to dynamically load and run, you can only obtain the corresponding class object first.
Get the object instance of Class:
1) Premise: if a specific class is known, this method is the most safe and reliable and has the highest program performance through the class attribute of the class. Example: class clazz = string class;
2) Premise: if the instance of a Class is known, call the getClass () method of the instance to obtain the Class object instance: Class clazz = obj getClass();
3) Premise: the full Class name of a Class is known, and the Class can be obtained through the static method forName() of Class under the Class path. Example: Class clazz = Class forName(“java.lang.String”);

Call the method in the class through reflection:
1. Find the Method: get a Method object through the getMethod(String name,Class... parameterTypes) Method of Class class, and set the parameter type required for the operation of this Method.
Method declaredMethod= clazz.getDeclaredMethod("methodName", Class...parameterTypes)
2. Call method: then use Object invoke(Object obj, Object[] args) to call and pass the parameter information of the obj object to be set to the method.
declaredMethod.invoke(obj,Object... args). Obj is the object that calls the method.
Note: if the original method is declared as private, you need to explicitly call the setAccessible(true) method of the method object before calling this invoke() method to access the private method.
declaredMethod.setAccessible(true);

Topics: Java Design Pattern