dynamic agent
Dynamic proxy, define an interface, the agent and the proxy class need to implement the interface, this is not flexible enough, the proxy class can only proxy the class that implements the interface.
Very inflexible, if the proxy class does not implement the interface, then you need to rewrite a proxy class. For logging, transactions, these operations are business-neutral, i.e., there is no need to specify that they all implement a certain interface. Therefore, the emergence of dynamic proxies
java kind of dynamic proxy generation is probably three kinds of JDK dynamic proxy, instrument dynamic proxy, cglib dynamic proxy. Among them, the first two are JDK comes with, cglib is the need for third-party dependencies to use.
- JDK Dynamic Proxy: Dynamically generate proxy classes during program execution.This proxy class implements the interface of the proxied class, so the proxied class must implement the interface when used.;
- Instrument dynamic proxy: is realized by adding interceptors to the Class byte file during the process of loading it into memory and dynamically modifying the byte file;
- cglib: dynamically generates proxy classes as the program runs.The proxy class is implemented by inheriting from the proxied class, so it cannot proxy a class that is modified by final.
- Both the JDK dynamic agent and the cglib dynamic agent are underpinned by theASM;
JDK Dynamic Proxy
Let's start with a program like this
/** Interfaces**/ public interface Mobile { void move(); } /** Proxy class */ public class Car implements Mobile{ @Override public void move() { ("move..."); } } /** Use of dynamic agents */ public class Test { public static void main(String[] args) { Car car = new Car(); ().put("",true); Mobile proxyInstance = (Mobile) ((), (), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { long before = (); (()+"Methods are performed before..."); Object invoke = (car, args); (()+"After the method is executed."); long after = (); ("Time consuming:" + (after - before)); return null; } }); (); } }
Creating a proxy class requires a call to the () method, which has three parameters
- First parameter: a class loader, typically using the class loader of the class being proxied
- Second parameter: the interface implemented by the proxied class
- Third parameter: an implementation class of the InvocationHandler interface
You can change the creation of dynamic proxies like this: write your own class to implement InvocationHandler.
public class Test { public static void main(String[] args) { Car car = new Car(); ().put("", "true"); Mobile proxyInstance = (Mobile) ((), (), new MyInvocationHandler(car)); (); } } class MyInvocationHandler implements InvocationHandler{ private Car car; public MyInvocationHandler(Car car) { = car; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { long before = (); (()+"Methods are performed before..."); Object invoke = (car, args); (()+"After the method is executed."); long after = (); ("Time consuming:" + (after - before)); return null; } }
To understand the JDK dynamic agent must be viewed dynamically generated agent class, through the setting of the JDK dynamic agent class generated by whether to save an attribute will be generated to save the proxy class, by adding the program before starting:
().put("",true);
Proxy class invocation process
- Generated Proxy Classes
public final class $Proxy0 extends Proxy implements Mobile { private static Method m1; private static Method m3; private static Method m2; private static Method m0; public $Proxy0(InvocationHandler var1) throws { super(var1); } public final boolean equals(Object var1) throws { try { return (Boolean)(this, m1, new Object[]{var1}); } catch (RuntimeException | Error var3) { throw var3; } catch (Throwable var4) { throw new UndeclaredThrowableException(var4); } } public final void move() throws { try { (this, m3, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } public final String toString() throws { try { return (String)(this, m2, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } public final int hashCode() throws { try { return (Integer)(this, m0, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } static { try { m1 = ("").getMethod("equals", ("")); m3 = ("").getMethod("move"); m2 = ("").getMethod("toString"); m0 = ("").getMethod("hashCode"); } catch (NoSuchMethodException var2) { throw new NoSuchMethodError(()); } catch (ClassNotFoundException var3) { throw new NoClassDefFoundError(()); } } }
- You can see that the proxy class inherits Proxy and implements the Mobile interface we defined
- The constructor method passes in the InvocationHandler type and assigns it to the h parameter in the parent Proxy class, and you can guess that this is the third parameter when getting the proxy class;
- The proxy class generates four methods through reflection, in addition to equals, toString, hashCode in Object the other is the method we want to proxy move;
- The move method calls (this, m3, (Object[])null), the invoke method in MyInvocationHandler.
- So when the invoke method of the proxy class is called, it is the invoke method in MyInvocationHandler that is called.
Method class
This class is a method class, to put it bluntly, it is a method template, in this class there is a method invoke, pass two parameters, one is the object that calls the method, the other is the method's entry parameter
Invoke method in InvocationHandler
You can see that the invoke method is called in the proxy class as (this, m3, (Object[])null); the
The invoke method in MyInvocationHandler:
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { long before = (); (()+"Methods are performed before..."); Object invoke = (car, args); (()+"After the method is executed."); long after = (); ("Time consuming:" + (after - before)); return null; }
Parameters:
- First parameter: this, the proxy class itself
- Second parameter: m3, the move method.
- The third parameter: the entry of the second method
Return Value:
This return value is actually the return value of the proxied method, if there is no return value then null is returned.
The most important thing here is (car, args), which is calling the move method with the car object.
ASM
In the above analysis, the parameters in the constructor method of the dynamic proxy class are what we guessed. Actually, it is implemented here using ASM. The () called while generating the proxy class passes in the implementation class of the InvocationHandler interface, and () dynamically generates the proxy class and produces a proxy object. Here to follow up on the study.
ASM is a Java bytecode manipulation framework , it can modify the existing class in binary form , or dynamically generate classes , ASM can directly generate a binary class file , you can also dynamically change the behavior of the class before the class is loaded into the Java Virtual Machine . ASM reads the information from the class file , the ability to change the behavior of the class , analyze the class information , and even according to the user's requirements to generate new classes .
cglib dynamic agent
public class Test { public static void main(String[] args) { Enhancer enhancer = new Enhancer(); (); (new MyMethodInterceptor()); Plane o = (Plane)(); (); } } class MyMethodInterceptor implements MethodInterceptor{ @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { long before = (); (()+"Methods are performed before..."); Object result = (o, objects); (()+"After the method is executed."); long after = (); ("Time consuming:" + (after - before)); return result; } }
The principle of cglib dynamic proxy is:
- Specify the parent class of the proxy class
- Generating Proxy Classes
- Calling the method of the proxy's parent class
summarize
The above is a personal experience, I hope it can give you a reference, and I hope you can support me more.