java Dynamic Proxy

Keywords: Java

proxy pattern
Proxy mode is one of 23 design modes. It refers to A mode in which an object A can have the same behavior as B by holding another object B. In order to open the protocol to the outside world, B often implements an interface, and A will also implement the interface. However, B is A "real" implementation class, while A is more "virtual". He borrows the method of B to implement the method of the interface. Although A is A "puppet army", it can enhance B and do other things before and after calling B's method. Spring AOP uses A dynamic proxy to complete the dynamic "weaving" of code.

The advantages of using an agent are more than these. If a project depends on the interface given by another project, but the interface of another project is unstable and the protocol is often changed, an agent can be used. When the interface is changed, only the agent needs to be modified, and the business code does not need to be modified one by one. In this sense, we can do this for all external interfaces to prevent external code from invading our code. This is called defensive programming. There may be many other applications of agent.

In the above example, class A writes and holds B, which is the static proxy of B.
There are two common implementations of dynamic agent, jdk dynamic agent and cglib dynamic agent.

The Proxy class (this type is the "new type" of $Proxy + number, which is dynamically generated) proxies the InvocationHandler, and the InvocationHandler proxies our class B, two-level Proxy.
Dynamic proxy is to generate a wrapper class object (implement the InvocationHandler interface). The InvocationHandler contains the proxied object and invokes the method of the proxy object through reflection (Object result = method.invoke(target, args)), which can be enhanced before and after the call.
It can be seen from the principle that JDK dynamic agent is the agent of "object".

public class PackTarget implements InvocationHandler{
    // Target class, delegate class, that is, the proxy object
    private Object target;
    public void setTarget(Object target){
        this.target = target;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{
        // You can enhance it here
        Object result = method.invoke(target, args);
        // You can enhance it here
        return result;
    }
    
    // Generate proxy class
    public Object CreatProxyedObj()
    {
        return ;
    }  
   
}
		
		// Target class and delegate class objects, that is, proxied objects
		TargetInterface target= new Target();
		//Wrapper class object
        PackTarget packTarget= new PackTarget ();
        packTarget.setTarget(target); 
        //Proxy object, and then you can call the method through the proxy object
		TargetInterface proxyXXX = (Target )Proxy.newProxyInstance(
				target.getClass().getClassLoader(),
				target.getClass().getInterfaces(), packTarget);
		//The first parameter delegates the Classloader class loader of the class
		//The second parameter is the interface information of the delegate class (mainly the definition of the method)
		//The third parameter wraps the class object
				

Let's take a look at how the dynamic proxy class invokes the InvocationHandler and why an invoke method of the InvocationHandler can distribute all methods of the target
The ProxyXXX created by Proxy is a subclass of itself and implements the interface of the target class

//Simplified ProxyXXX (proxy class)
public final class ProxyXXX extends Proxy implements TargetInterface{
//These variables are initialized in the static static code block. These variables are necessary input parameters when invoking the invocationhandler. They also let us vaguely see the traces left by the Proxy when generating ProxyXXX
  	private static Method m0;
  	private static Method m1;
  	...
  	static{
  	 	m0 = Class.forName("XXX.TargetInterface ").getMethod("methodName0", new Class[0]);
      	m1 = Class.forName("XXX.TargetInterface ").getMethod("methodName1", new Class[] { Class.forName("java.lang.String") });
    	m2 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
      	m3 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
      	m4 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
  	}
	public final String methodName0(String paramString){
		return (String)this.h.invoke(this, m0, new Object[] { paramString });
	}
	public final String methodName1(String paramString){
		return (String)this.h.invoke(this, m1, new Object[] { paramString });
	}
}

You can see that all the methods in ProxyXXX (Proxy class) are implemented by calling h, where h is the InvocationHandler, which is the third parameter we pass when generating ProxyXXX (Proxy object). Another key point here is that the methodName0 method (business method) must correspond to the parameter m0 passed when invoking the invoke method one by one, but these are transparent to us and guaranteed by the Proxy during newProxyInstance. Notice that ProxyXXX passes this to the past when invoking. The first method of invokehandler's invoking is our dynamic Proxy instance, which can be used when business needs it. (so don't distribute the request to the first parameter in the invoke method, otherwise it will obviously be an endless loop.)

--------
Copyright notice: This is the original article of CSDN blogger "Zhao Jufei", which follows the CC 4.0 BY-SA copyright agreement. Please attach the original source link and this notice for reprint.
Original link: https://blog.csdn.net/flyfeifei66/article/details/81481222










--------
Copyright notice: This article is CSDN Blogger「Zhao Jufei」Original articles, follow CC 4.0 BY-SA Copyright agreement, please attach the original source link and this statement.
Original link: https://blog.csdn.net/flyfeifei66/article/details/81481222

Posted by Stoneguard on Tue, 09 Nov 2021 14:21:14 -0800