WHAT
Dynamic agent is a kind of agent mode. Agent mode refers to that the agent helps the proxy object complete what should be completed by the proxy object. Agents usually have more powerful capabilities and are more professional than the objects they are represented. Take an example in life to illustrate that you can choose to find the landlord and sign a contract to complete the house lease. However, we usually do not do this in life, but seek more professional intermediaries to act as agents for us and find landlords with rental intention. In this example, finding a house should have been completed by yourself, but it has become completed by an intermediary. You don't need to worry about how to complete it. This model is called the agent model.
WHY
Why is there an agent model?
The great progress of mankind comes from the division of labor and cooperation. Special people do special tasks and perform their respective duties, which can speed up the promotion of business without requiring everyone and every organization to be all-round. Everyone just needs to focus on their own one-third of an acre and hand over extra work to more professional people. You just have to 'sit back and enjoy your success'.
WHERE
It applies to everything you don't want to do, such as finding Ding Dong to buy vegetables for you
HOW
The above are ideological statements. How can we implement them in our Java world?
! [(C:\Users \ Huang Xiaosi \ appdata \ roaming \ typora \ typera user images \ image-20210822120809841. PNG)
In order to improve the reusability of the code, the intermediary will sometimes call the lazy method directly, and sometimes do not call the lazy method directly. Where is the logic of using the lazy method implemented?
[the external chain image transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-W8beLQPp-1629608306470)(C:\Users \ Huang Xiaosi \ appdata \ roaming \ typora user images \ image-20210822123645684. PNG)]
InvocationHandler interface
All mediations must be the implementation class of InvocationHandler interface, and need to implement the Invoke method, which is the method that specifically determines the execution logic of the mediation.
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; /** * InvocationHandler Is the class that determines the specific proxy logic * @author yhg 2021-08-22 12:13 */ public class MyProxyHandler implements InvocationHandler { private Object lazyPerson; public MyProxyHandler(Object lazyPerson) { this.lazyPerson = lazyPerson; } public Object getLazyPerson(){ return lazyPerson; } /** * * @return Return mediation object */ public Object getProxy(){ return Proxy.newProxyInstance(this.getClass().getClassLoader(),lazyPerson.getClass().getInterfaces(),this); } /** * All actions that should be initiated by lazy people will be intercepted. After intercepting, this method will be executed. Here you can determine the specific logic of how the intermediary operates * @param proxy intermediary * @param method Proxy method * @param args Parameters of the proxied method * @return * @throws Throwable */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { String res = null; System.out.println("intermediary:I'm looking for a house. Just sit down, lazy man"); //If the intermediary decides not to find a lazy person to see the last house, the lazy person can not appear in the whole process of agent looking for a house System.out.println("intermediary:I've found the last house left. Let's go and see the house together"); ((FindHouse)lazyPerson).findHouse(); System.out.println("The intermediary and the lazy finally determined the house A"); return "house A"; } }
Java face object, how is the mediation object generated?
public Object getProxy(){ return Proxy.newProxyInstance(this.getClass().getClassLoader(),lazyPerson.getClass().getInterfaces(),this); }
The mystery is in the above line of code. This is the method provided by JDK to generate a class file and load a virtual machine at runtime.
Class loader classLoader is required because class files need to be loaded
To intercept lazy people's methods, you need to know which methods to intercept. These methods are defined in the interface
After intercepting the method, I need the InvocationHandler to tell me how to execute the logic, so I need this
What does the Java dynamically generated proxy class file look like
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by Fernflower decompiler) // package com.sun.proxy; import com.yhg.FindHouse; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.lang.reflect.UndeclaredThrowableException; public final class $Proxy0 extends Proxy implements FindHouse { 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)super.h.invoke(this, m1, new Object[]{var1}); } catch (RuntimeException | Error var3) { throw var3; } catch (Throwable var4) { throw new UndeclaredThrowableException(var4); } } public final String findHouse() throws { try { return (String)super.h.invoke(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)super.h.invoke(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)super.h.invoke(this, m0, (Object[])null); } catch (RuntimeException | Error var2) { throw var2; } catch (Throwable var3) { throw new UndeclaredThrowableException(var3); } } static { try { m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object")); m3 = Class.forName("com.yhg.day3.FindHouse").getMethod("findHouse"); m2 = Class.forName("java.lang.Object").getMethod("toString"); m0 = Class.forName("java.lang.Object").getMethod("hashCode"); } catch (NoSuchMethodException var2) { throw new NoSuchMethodError(var2.getMessage()); } catch (ClassNotFoundException var3) { throw new NoClassDefFoundError(var3.getMessage()); } } }
You can see that all the Proxy classes produced are subclasses of Proxy and are implemented in turn according to the interface type you pass in
public $Proxy0(InvocationHandler var1) throws { super(var1); } // The following is the code of super protected Proxy(InvocationHandler h) { Objects.requireNonNull(h); this.h = h; }
You can see that the constructor saves the InvocationHandler we passed in to the h attribute of the parent class
Looking back, the methods of each proxy class are executed
return (XXXX)super.h.invoke(this, mXXX, (Object[])null);
Note that the proxy class will finally execute the invoke method of the InvocationHandler we passed in
So far, all logic has been sorted out
The following is the rest of the code. The InvocationHandler class has been posted above
/** * @author yhg 2021-08-22 12:12 */ public interface FindHouse { String findHouse(); }
/** * @author yhg 2021-08-22 12:13 */ public class LazyPerson implements FindHouse { @Override public String findHouse() { System.out.println("The lazy man is looking for a house"); return ""; } }
/** * @author yhg 2021-08-22 12:23 */ public class FindHouseDemo { public static void main(String[] args) { // System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true"); System.getProperties().put("jdk.proxy.ProxyGenerator.saveGeneratedFiles", "true"); // Either of the above two lines of code can save the generated proxy class file in the project com\sun\proxy for easy understanding FindHouse proxy = (FindHouse)new MyProxyHandler(new LazyPerson()).getProxy(); String house = proxy.findHouse(); System.out.println("The intermediary found it" + house); } }
Code run results
intermediary:I'm looking for a house. Just sit down, lazy man intermediary:I've found the last house left. Take the lazy man to see the house The lazy man is looking for a house The intermediary and the lazy finally determined the house A The agent found the house A
MyProxyHandler(new LazyPerson()).getProxy();
String house = proxy.findHouse();
System.out.println("intermediary found" + house);
}
}
Code run results ```java intermediary:I'm looking for a house. Just sit down, lazy man intermediary:I've found the last house left. Take the lazy man to see the house The lazy man is looking for a house The intermediary and the lazy finally determined the house A The agent found the house A