10 minutes to understand the dynamic proxy in Java, 10 minutes to java
Ten minutes to help you understand the dynamic proxy in Java. What is dynamic proxy? For more information, see
If the proxy class already exists before the program runs, this proxy method is used as a static proxy. In this case, the proxy class is usually defined in Java code. Generally, the proxy class and delegate class in the static proxy implement the same interface or derive from the same parent class.
I. Overview
1. What is proxy?
We all know that micro-commerce agents, simply put, are used to sell goods instead of manufacturers, and manufacturers "entrust" agents to sell goods for them. As for micro-commerce agents, we often do not know who the manufacturers are when we buy things from them. That is to say, the "delegate" is invisible to us. Secondly, micro-commerce agents are mainly targeting customers in the circle of friends, which is equivalent to "filtering" the customer group for manufacturers ". We further abstract derivative agents and manufacturers. The former can be abstracted as a proxy class, and the latter can be abstracted as a delegate class (by proxy class ). By using proxy, there are usually two advantages that correspond to the two features of the WeChat agent we mentioned:
Advantage 1:You can hide the implementation of the delegate class;
Advantage 2:This decoupling can be implemented between the customer and the delegate class, and some additional processing can be done without modifying the delegate class code.
2. Static proxy
If the proxy class already exists before the program runs, this proxy method is used as a static proxy. In this case, the proxy class is usually defined in Java code. Generally, the proxy class and delegate class in the static proxy implement the same interface or derive from the same parent class. The following describes the simple implementation of static proxy by using the Vendor class to represent the manufacturer and BusinessAgent class to represent the derivative agent. The delegate class and proxy class both implement the producer interface. The producer interface is defined as follows:
Public interface detail {void detail (); void ad ();} the Vendor class is defined as follows: public class Vendor implements detail {public void detail () {System. out. println ("In your method");} public void ad () {System, out. println ("ad method ")}}
The proxy BusinessAgent is defined as follows:
public class Vendor implements Sell { public void sell() { System.out.println("In sell method"); } public void ad() { System,out.println("ad method") } }
We can understand from the definition of the BusinessAgent class that the static proxy can be implemented through aggregation, so that the proxy class can hold a reference of the delegate class.
Next, let's consider this requirement: Add a filter function for the Vendor class and only sell the goods to college students. Through static proxy, we can implement it without modifying the code of the Vendor class. You only need to add a judgment in the Evaluate Method of the BusinessAgent class as follows:
public class BusinessAgent implements Sell { ... public void sell() { if (isCollegeStudent()) { vendor.sell(); } } ... }
This corresponds to the second advantage of using proxy as mentioned above: decoupling between the customer and the delegate class can be realized, and some additional processing can be done without modifying the delegate class code. The limitation of static proxy is that the proxy class must be compiled before running. Next we will focus on the dynamic proxy method for generating proxy classes during runtime.
Ii. Dynamic proxy
1. What is dynamic proxy
The proxy method created when the agent class is running is used as a dynamic proxy. In other words, in this case, the proxy class is not defined in the Java code, but is dynamically generated at runtime according to the "Instructions" in the Java code. Compared with static proxy, dynamic proxy can easily process proxy functions in a unified manner without modifying the functions of each proxy class. This is more abstract. Next we will introduce how this advantage of dynamic proxy is embodied with an instance.
Now, let's assume that we want to implement this requirement: output "before" before executing the methods in the delegate class, and output "after" after execution ". In the above example, we will introduce the Vendor class as the delegate class and the BusinessAgent class as the proxy class. First, we can use static proxy to implement this requirement. The relevant code is as follows:
public class BusinessAgent implements Sell { private Vendor mVendor; public BusinessAgent(Vendor vendor) { this.mVendor = vendor; } public void sell() { System.out.println("before"); mVendor.sell(); System.out.println("after"); } public void ad() { System.out.println("before"); mVendor.ad(); System.out.println("after"); } }
From the above code, we can understand that to implement our requirements through static proxy, we need to add the corresponding logic in each method. Here there are only two methods, so the workload is not large, what if the explain Interface contains hundreds of methods? At this time, the use of static proxy will write a lot of redundant code. By using dynamic proxy, we can make a "Uniform indication" to uniformly process all proxy methods without having to modify each method one by one. Next we will introduce how to use dynamic proxy to meet our needs.
2. Use Dynamic proxy
(1) InvocationHandler Interface
When using dynamic proxy, we need to define an intermediary class between the proxy class and the delegate class, which is required to implement the InvocationHandler interface. The interface is defined as follows:
public interface InvocationHandler { Object invoke(Object proxy, Method method, Object[] args); }
From the InvocationHandler name, we can know that the intermediary class implementing this interface is used as a "Call processor ". When we call the method of the proxy class object, this "call" will be transferred to the invoke method, the proxy class object is passed in as the proxy parameter, the parameter method identifies which method we call the proxy class, And args is the parameter of this method. In this way, the call to all methods in the proxy class will become the call to invoke, in this way, you can add a unified processing logic to the invoke method (or you can perform different processing on different proxy methods based on the method parameter ). Therefore, we only need to output "before" in the invoke method implementation of the intermediary class, then call the invoke method of the delegate class, and then output "after ". Next we will implement it step by step.
(2) definition of the delegate class
In the dynamic proxy mode, the delegate class must implement an interface. Here we implement the delegate interface. The principal class Vendor class is defined as follows:
public class Vendor implements Sell { public void sell() { System.out.println("In sell method"); } public void ad() { System,out.println("ad method") } }
(3) intermediary
As mentioned above, the intermediary class must implement the InvocationHandler interface and act as the call processor to intercept the call to the proxy method. The definition of an intermediary class is as follows:
Public class DynamicProxy implements InvocationHandler {private Object obj; // obj is the delegate class Object; public DynamicProxy (Object obj) {this. obj = obj ;}@ Override public Object invoke (Object proxy, Method method, Object [] args) throws Throwable {System. out. println ("before"); Object result = method. invoke (obj, args); System. out. println ("after"); return result ;}}
From the code above, we can see that the intermediary class holds a delegate Class Object Reference and calls the corresponding method of the delegate Class Object (line 1) in the invoke method. Does it seem familiar? By holding the delegate Class Object Reference through aggregation, the external calls to invoke are eventually converted into calls to the delegate class object. Isn't this an implementation method of the static proxy we introduced above? In fact, the intermediary class and the delegate class constitute a static proxy relationship. In this relationship, the intermediary class is the proxy class, and the delegate class is the delegate class. The proxy class and the intermediary class also constitute a static proxy relationship. In this relationship, the intermediary class is the delegate class, and the proxy class is the proxy class. That is to say, the dynamic proxy relationship is composed of two static proxy relationships, which is the principle of the dynamic proxy. Next we will introduce how to "instruct" to dynamically generate proxy classes.
(4) dynamically generate proxy classes
The code for dynamically generating proxy classes is as follows:
Public class Main {public static void main (String [] args) {// create an intermediate class instance DynamicProxy inter = new DynamicProxy (new Vendor ()); // Add this statement to generate a $ Proxy0.class file, which is a dynamically generated proxy file System. getProperties (). put ("sun. misc. proxyGenerator. saveGeneratedFiles "," true "); // obtain the Proxy instance quota = (percent) (Proxy. newProxyInstance (response. class. getClassLoader (), new Class [] {category. class}, inter); // call the proxy class method through the proxy class object, which will actually be transferred to the invoke method to call the handler. values (); values. ad ();}}
In the above Code, we call the newProxyInstance method of the Proxy class to obtain a Proxy class instance. This proxy class implements the specified interface and distributes method calls to the specified call processor. The statement for this method is as follows:
Copy the Code as follows: public static Object newProxyInstance (ClassLoader loader, Class <?> [] Interfaces, InvocationHandler h) throws IllegalArgumentException
The three parameters of the method are described as follows:
Loader:Defines the ClassLoder of the proxy class;
Interfaces:List of proxy Implemented interfaces
H:Call the processor, that is, the class instance defined above that implements the InvocationHandler Interface
Run the following command to check whether our dynamic proxy works properly. The output after running here is:
It indicates that our dynamic proxy is indeed effective.
We have briefly mentioned the principle of dynamic proxy. Here we will briefly summarize: first, we can get the proxy class instance through the newProxyInstance method, and then we can call the proxy class method through this proxy class instance, in fact, calls to proxy Methods call the invoke method of the intermediary class (call the processor). In the invoke method, we call the corresponding methods of the delegate class and can add our own processing logic.