Dynamic agent (JDK agent)
Let's start with a few points:
What is dynamic agent?
Dynamic agents are still agents in essence
However, the relationship between the agent and the represented object is dynamically determined. For example, Wang Ergou's colleague Niu Cuihua did not determine her attorney before the court session, but chose a lawyer in court on the day of the court session, which is mapped to the programming field. This relationship is determined at run time.
Let's illustrate it with code
Why use dynamic proxy?
Since the dynamic agent does not enhance any functions of the agent for us, why should we use the dynamic agent? Isn't the static agent very good?
Whatever is determined dynamically probably has the advantages of flexibility and strong expansion.
Review of static agency: static agency refers to the pre-determined relationship between the agent and the agent. For example, Fang Wenjing, Wang Ergou's lawyer, was determined before the court session. If it is mapped to the programming field, it means that the dependency between the proxy class and the proxy class is determined during compilation.
As shown in the following code: the proxy object is the object of the implementation class of ITeacherDao
Moreover, the proxy object needs to implement the same interface as the target object, so there will be many proxy classes.
public class TeacherDaoProxy implements ITeacherDao{ //The target object of the agent is aggregated through the interface private ITeacherDao target; //The constructor receives the proxied object public TeacherDaoProxy(ITeacherDao target) { this.target = target; } @Override public void teach() { System.out.println("Start agent...Complete some methods"); target.teach(); System.out.println("Submit..."); } }
If we use dynamic proxy, we only need to generate one proxy class, and only one proxy class is needed in the whole process, because we can dynamically hand over many things of the proxied objects to this proxy class.
JDK dynamic proxy implementation
In the dynamic Proxy mechanism of java, there are two important classes or interfaces. One is the InvocationHandler interface and the other is the Proxy class. This class and interface must be used to implement our dynamic Proxy.
InvocationHandler interface is implemented for dynamic proxy class and is responsible for handling the operation of the proxy object;
Proxy is used to create a dynamic proxy class instance object, because only with this object can we call those methods that need proxy.
Dynamic proxy code implementation
See the following code:
For the convenience of understanding, I'll start with the client Java, that is, the class containing the main function
Client
package com.zbz.Design mode.proxy.jdkproxy; public class Client { public static void main(String[] args) { IAnimal rabbit = new Rabbit(); IPeople zhangsan = new ZhangSan(); //The following two different proxies are represented by the same proxy class dynamicproxy (below) //That is, the same agent class acts as the agent for rabbit and Zhang San //The rabbit's agent is looking for water to drink IAnimal rabbitProxy = (IAnimal)ProxyFactory.getDynamicProxyInstance(rabbit); rabbitProxy.drink(); //Zhang San's agent is looking for water to drink IPeople zhangsanProxy = (IPeople) ProxyFactory.getDynamicProxyInstance(zhangsan); zhangsanProxy.drink(); } }
We used the Proxy object rabbitProxy generated by the newProxyInstance() method of Proxy class to call rabbitProxy drink(); The system will distribute this method to invoke(), where the rabbitProxy object class is dynamically produced by the system, which implements our business interface IAnimal. zhangsanProxy is no exception. It can be seen from the result diagram that the name generated by the system is P r o x y 0 and Proxy0 and Proxy0 and Proxy1
ProxyFactory
The static factory provides a method to get the proxy object
package com.zbz.Design mode.proxy.jdkproxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; public class ProxyFactory { public static Object getDynamicProxyInstance(Object target){ InvocationHandler handler = new DynamicProxy(target); return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), handler); } }
/** * newProxyInstance Method parameter description * The first parameter classloader: Specifies the class loader used by the current target object; * The second parameter is class <? > Interfaces: the interface type implemented by the target object, which is confirmed by the generic method; * The third parameter InvocationHandler h: event handling. When the method of the target object is executed, the event handler method will be triggered The currently executed target object method will be passed in as a parameter */ @CallerSensitive public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
DynamicProxy
Build a dynamic proxy class
package com.zbz.Design mode.proxy.jdkproxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class DynamicProxy implements InvocationHandler { private Object target;//Proxied object public DynamicProxy(Object obj){ this.target=obj; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println(proxy.getClass()+" Start agent: "+method.getName()); Object returnValue = method.invoke(target,args); return returnValue; } }
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
The parameters of this method have the following meanings:
Proxy: represents a dynamic proxy object
Method: represents the method being executed
args: represents the argument passed in by the current execution method
Return value: indicates the return value of the currently executed method
In the above case, we used the Proxy object rabbitProxy generated by the newProxyInstance() method of Proxy class to call rabbitProxy drink(); Operation, the system will distribute this method to invoke() (that is, invoke(...) of the Proxy class) The rabbitProxy object class is dynamically produced by the system, which implements our business interface IAnimal.
Rabbit
rabbit
package com.zbz.Design mode.proxy.jdkproxy; public class Rabbit implements IAnimal{ @Override public void drink() { System.out.println("The rabbit wants water"); } }
ZhangSan
Zhang San
package com.zbz.Design mode.proxy.jdkproxy; public class ZhangSan implements IPeople { @Override public void drink() { System.out.println("Zhang San wants to drink water"); } }
IAnimal
package com.zbz.Design mode.proxy.jdkproxy; public interface IAnimal { void drink(); }
IPeople
package com.zbz.Design mode.proxy.jdkproxy; public interface IPeople { void drink(); }
Principle of JDK dynamic agent implementation
First of all, the implementation method of dynamic agent of Jdk depends on the interface. First, use the interface to define the operation specification. (such as drink() in IAnimal and ipeple)
Then, the Proxy object generated by the Proxy class calls the operation of the Proxy object, and this operation is distributed to the invoke method of the InvocationHandler interface for specific execution