If the proxy class already exists before the program runs, then this proxy method is called a static proxy. In this case, the proxy class is usually defined in Java code. Normally, the proxy class and delegate class in the static proxy implement the same interface or are derived from the same parent class.
1. Overview
1. What is an agent
We all know that wechat agents are simply selling goods on behalf of manufacturers, and the manufacturer "entrusted" agents to sell goods for them. Regarding WeChat business agents, first of all, when we buy things from them, we usually don’t know who the manufacturer is, that is, the “commissioner” is invisible to us; secondly, WeChat business agents mainly target people in the circle of friends as their customers, which is equivalent to a “filter” of the customer group for the manufacturer. We further abstract the micro-business agent and manufacturer. The former can be abstracted as an agent class, and the latter can be abstracted as a delegate class (agent class). By using a proxy, there are usually two advantages and can correspond to the two characteristics of the micro-business agent we mentioned:
Advantage 1: It can hide the implementation of the delegate class;
Advantage 2: It can achieve decoupling between the client and the delegate class, and can do some additional processing without modifying the delegate class code.
2. Static proxy
If the proxy class already exists before the program runs, then this proxy method is called a static proxy. In this case, the proxy class is usually defined in Java code. Normally, the proxy class and delegate class in the static proxy implement the same interface or are derived from the same parent class. Below we use the Vendor class to represent the manufacturer and the BusinessAgent class to represent the micro-business agent to introduce the simple implementation of static agents. Both the delegation class and the proxy class implement the Sell interface. The definition of the Sell interface is as follows:
public interface Sell { void sell(); void ad(); } The definition of the Vendor class is as follows: public class Vendor implements Sell { public void sell() { System.out.println("In sell method"); } public void ad() { System,out.println("ad method") } } The definition of the proxy class BusinessAgent is as follows:
public class Vendor implements Sell { public void sell() { System.out.println("In sell method"); } public void ad() { System,out.println("ad method") } } From the definition of the BusinessAgent class, we can understand that static agents can be implemented through aggregation, so that the agent class can hold a reference to the delegate class.
Let’s consider this requirement below: add a filtering function to the Vendor class and sell goods only to college students. Through static proxy, we can achieve it without modifying the code of the Vendor class. We just need to add a judgment to the sell method in the BusinessAgent class and it can be as follows:
public class BusinessAgent implements Sell { ... public void sell() { if (isCollegeStudent()) { vendor.sell(); } } ... } This corresponds to the second advantage of using a proxy mentioned above: it can achieve decoupling between the client and the delegate class, and can do some additional processing without modifying the delegate class code. The limitation of static proxy is that you must write a proxy class before running. Let’s focus on introducing the dynamic proxy method of generating proxy classes at runtime.
2. Dynamic Agent
1. What is dynamic proxy
The proxy method created by the proxy class when the program is run is called a dynamic proxy. That is, in this case, the proxy class is not defined in the Java code, but is dynamically generated at runtime based on our "instructions" in the Java code. Compared with static proxy, the advantage of dynamic proxy is that it can easily handle functions of proxy class uniformly without modifying functions of each proxy class. This is more abstract. Let’s combine an example to introduce how the advantages of dynamic proxy are reflected.
Now, suppose we want to implement the requirement: output "before" before executing the method in the delegate class, and output "after" after executing. We will introduce the Vendor class as the delegate class in the example above, and the BusinessAgent class as the proxy class. First, let’s use a static proxy to achieve 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 implementing our needs through static proxy requires us to add corresponding logic to each method. There are only two methods here, so the workload is not large. What if the Sell interface contains hundreds of methods? At this time, using static proxy will write a lot of redundant code. By using dynamic proxy, we can make a "uniform indication" to uniformly process all proxy classes' methods without modifying each method one by one. Let’s introduce how to use dynamic proxy to implement our needs.
2. Use dynamic proxy
(1) When using dynamic proxy in the InvocationHandler interface, we need to define an intermediary class located between the proxy class and the delegate class. This intermediary class is required to implement the InvocationHandler interface. The definition of this interface is as follows:
public interface InvocationHandler { Object invoke(Object proxy, Method method, Object[] args); } From the name InvocationHandler we can know that the mediation class that implements this interface is used as the "call processor". When we call the method of the proxy class object, this "call" will be forwarded to the invoke method. The proxy class object is passed in as a proxy parameter. The parameter method identifies which method we call the proxy class. args is the parameter of this method. In this way, our calls to all methods in the proxy class will become calls to invoke, so we can add unified processing logic to the invoke method (or different methods of the proxy class can be processed according to the method parameters). Therefore, we only need to output "before" in the invoke method implementation of the mediation class, then call the invoke method of the delegate class, and then output "after". Let’s implement it step by step.
(2) Under the dynamic proxy method of delegate class, the delegate class must implement a certain interface. Here we implement the Sell interface. The definition of the Vendor class is 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) Mediation class As mentioned above, the mediation class must implement the InvocationHandler interface, as the call processor "intercept" calls to the proxy class methods. The definition of the intermediary class is as follows:
public class DynamicProxy implements InvocationHandler { private Object obj; //obj is a 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 above code, we can see that the intermediary class holds a delegate object reference, and the corresponding method of the delegate object is called in the invoke method (line 11). Do you think it seems familiar when you see this? Holding the delegate object reference through aggregation method, ultimately converting all external calls to invoke into calls to the delegate object. Isn't this an implementation method of static proxy we introduced above? In fact, the intermediary class and the delegate class form a static proxy relationship. In this relationship, the intermediary class is a proxy class, and the delegate class is a delegation class; the proxy class and the intermediary class also form a static proxy relationship. In this relationship, the intermediary class is a delegation class and the proxy class is a proxy class. In other words, the dynamic proxy relationship consists of two sets of static proxy relationships, which is the principle of dynamic proxy. Let's introduce how to "instruct " dynamically generate proxy classes.
(4) Dynamic Generation Proxy Class Dynamic Generation Proxy Class Relevant codes are as follows:
public class Main { public static void main(String[] args) { //Create an instance of the mediation class DynamicProxy inter = new DynamicProxy(new Vendor()); //Add this sentence will generate a $Proxy0.class file, which is the dynamically generated proxy class file System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true"); //Get the proxy class instance sell Sell sell = (Sell)(Proxy.newProxyInstance(Sell.class.getClassLoader(), new Class[] {Sell.class}, inter)); //Calling the proxy class method through the proxy class object will actually go to the invoke method to call sell.sell(); sell.ad(); } } In the above code, we call the newProxyInstance method of the Proxy class to get a proxy class instance. This proxy class implements the interface we specified and will distribute method calls to the specified calling processor. The declaration of 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 as follows:
loader: defines the ClassLoder of the proxy class;
interfaces: List of interfaces implemented by proxy class
h: Call the processor, that is, the class instance we defined above that implements the InvocationHandler interface, let's run it to see if our dynamic proxy can work properly. The output I run here is:
This shows that our dynamic proxy is indeed working.
We have briefly mentioned the principle of dynamic proxy above. Here we will briefly summarize: First, we can obtain the proxy class instance through the newProxyInstance method, and then we can call the proxy class method through this proxy class instance. In the proxy class method, we will actually call the invoke method of the mediation class (called the processor). In the invoke method, we call the corresponding method of the delegate class and can add our own processing logic.
The above is all the content of this article. I hope it will be helpful to everyone's learning and I hope everyone will support Wulin.com more.