Life is too short to have a dog

First, start from a daigou

Some time ago, my wife took a fancy to a belt of unknown brand. She searched the domestic stores and found that none of them had any goods. So she went to ask her little sister who was a purchasing agent to make this kind of belt. Looking at her this one operation, I can’t help but feel a familiar, this act as purchasing agency mode and agent mode How similar, act as purchasing agency little sister instead of the actual location to actual customer for trial and purchase of goods, and then sent to the corresponding customer, in the process, customers only need to tell little sister bought need to buy something.

Second, basic concepts

1. What is the agency mode

Proxy pattern is an object structure design pattern that controls access to target objects by introducing a proxy object. The proxy object acts as a mediator between the client object and the target object, masking content that the client object does not need to be aware of or adding some additional processing power.

As you can see from the class diagram above, in order for the client to treat the proxy object and the target object consistently, the client object needs to be programmed for the abstractions of both.

  • AbstractSubject: Abstract topic class, as the common interface/abstract class of the proxy object and the target object, provided to the client object for invocation;
  • ConcreteSubject: The specific subject class, the object that actually provides the functions required by the client object, in which the actual business processing is performed, is the actual object represented by the proxy object;
  • Proxy: proxy subject class, in the proxy object holds a reference to the actual object, in the actual object call at the same time, the proxy object also provides access control, create/delete the actual object, additional function processing capabilities;

2. A small example

Here is the proxy model to implement the above example of daigou.

AbstractShop

package ProxyPattern; 
​
 /** * Abstract mall class **@author brucebat
 * @version1.0 * / 
public abstract class AbstractShop { 
​
     /** 
      * 购买
      * 
      * @paramCommodityName commodityName */ 
     public abstract void buy(String commodityName); 
 } 
​
Copy the code

ConcreteShop

package ProxyPattern; 
​
 /** * Actual store class **@author brucebat
 * @version1.0 * / 
public class ConcreteShop extends AbstractShop { 
​
     /** * Quantity sufficiency check according to the commodity name **@paramCommodityName commodityName *@returnIs the quantity sufficient */ 
     public boolean checkEnough(String commodityName) { 
         return "Belt".equals(commodityName); 
     } 
​
     @Override
     public void buy(String commodityName) { 
         System.out.println("Buy" + commodityName + "Complete"); }}Copy the code

ShopProxy

package ProxyPattern; 
​
 /** * Commodity Agency **@author brucebat
 * @version1.0 * / 
public class ShopProxy extends AbstractShop { 
​
     private final ConcreteShop concreteShop; 
​
     public ShopProxy(a) { 
         this.concreteShop = new ConcreteShop(); 
     } 
​
     public void preBuy(String commodityName) { 
         boolean checkEnough = concreteShop.checkEnough(commodityName); 
         if (checkEnough) { 
             System.out.println("The current supply of goods is sufficient to purchase."); 
             return; 
         } 
         throw new NullPointerException("The item is currently out of stock."); 
     } 
​
     @Override
     public void buy(String commodityName) { 
         this.preBuy(commodityName); 
         concreteShop.buy(commodityName); 
         this.afterBuy(); 
     } 
​
     public void afterBuy(a) { 
         System.out.println("Complete purchase, start shipping."); }}Copy the code

The test class

package ProxyPattern; 
​
 / * * *@author brucebat
 * @version1.0 * / 
public class App { 
​
     public static void main(String[] args) { 
         AbstractShop abstractShop = new ShopProxy(); 
         abstractShop.buy("Belt"); }}Copy the code

Here are the results:

At present, the supply of goods is sufficient to purchase the beltCopy the code

Three, dynamic agent – all-round middleman

In the above concepts and examples, the proxy class and the target class are preexisting, their interfaces/abstract methods and the methods needed for the proxy are specified, and this proxy pattern is called static proxy. In this proxy mode, every target object that needs a proxy needs to write a corresponding proxy object, which will lead to the explosive growth of the number of classes in the system. So how to solve this problem? Dynamic proxies are born.

Dynamic proxy allows the system to dynamically create proxy objects according to actual needs at runtime, and allows the same proxy object to proxy different target objects and different methods. Two common dynamic proxy methods in Java are as follows:

1. JDK dynamic proxy

The JDK’s native dynamic Proxy relies on two main classes, Proxy and InvocationHandler, located in java.lang.Reflect.

  • Proxy: provides static methods for creating dynamic proxy classes and instance objects. It is also a superclass of the created dynamic proxy classes. During the creation of the dynamic proxy object, the correspondingInvocationHandleBound to it, the proxy object makes the actual business method call to the target object through the call handler.
  • InvocaitonHandler: is an interface implemented by the call handler of the proxy object. Each proxy object is associated with a call handler. When a proxy method is invoked on a proxy object, the method call is encoded and assigned to the invoke method of the corresponding call handler for execution. inInvocationHandlerWe can implement the above mentioned logic processing such as access control, additional function processing, and so onInvocationHandlerCan be written as generic logic for all classes or customized processing logic for a particular class.

Here we look at the specific Proxy provided to create dynamic Proxy class and create dynamic Proxy object method signature, method of specific source code is not listed, interested students can find:

  /** * create a proxy Class of type Class. In the parameter list, you can see the array of interfaces that need to provide the Class loader and the proxy. * Note that the array of interfaces needs to be the same as the interface list of the target class. * /  
public staticClass<? > getProxyClass(ClassLoader loader, Class<? >... interfaces)/** * This method returns a dynamically created proxy object. In the parameter list, you can see the array of interfaces that need to provide the classloader and the proxy, and the call handler. * /  
public static Object newProxyInstance(ClassLoader loader, Class
       [] interfaces, InvocationHandler h)  
Copy the code

As you can see from the above method signature, the JDK dynamic proxy proxies objects as interfaces, but not abstract and concrete classes. This shortcoming can be remedied with the following dynamic proxy tool.

2. CGLib

CGLib is a powerful code generation tool that extends Java classes and implements Java interfaces at runtime. Unlike JDK dynamic proxy, CGLib can proxy both interfaces, abstract classes, and concrete classes.

CGLib also provides two classes, Enhancer and MethodInterceptor, for dynamically creating a proxy class and intercepting method calls, respectively.

  • Enhancer: Different from Proxy,EnhancerInstead of generating a proxy object that contains an instance of the target object, dynamic subclasses are generated to enable method interception. In addition to implementing interfaces, it allows proxy objects to extend concrete base classes. Dynamically generated subclasses override the non-final methods of the superclass and have hooks that call back to the user-defined interceptor implementation.
  • MethodInterceptor: provides method dimension interception handling and is the first and most common type of callback (note that this refers to the CGLib class library)MethodInterceptor, rather than the AOP project). It is equivalent in AOP terminology“Surround Notification”This means that you can handle some custom logic before and after calling the super method (that is, the surrogate superclass method).

In general, both JDK dynamic proxy and CGLib dynamically create proxy objects by dynamically generating bytecode at run time. The difference is that JDK dynamic proxy can only proxy interfaces, and the relationship between the target object and the interface is an association relationship, while CGLib can proxy both interfaces and classes. Its relationship with the target class is inheritance, and the proxy processing is completed by overwriting the parent class method by dynamically generating the subclass method.

Four,

The proxy pattern can be said to be a very useful and important structural design pattern in daily development. It provides a solution to indirectly access and control the access to the target object. This solution allows us to make more flexible and extensible logical processing in the coding process, such as the remote proxy used in Java RMI. In the local development, we only need to use the remote proxy object as the local object. There is no need to worry about the serialization, network communication, and so on that the remote agent needs to do when it actually calls the method.

But this does not mean that the proxy pattern, there is no defect, just as there is no such thing as not earn price difference of middlemen, the realization of the proxy pattern introduces proxy objects, which brought the extra resources consumption, at the same time, some proxy pattern implementation logic is relatively complex, to implement more difficult and time-consuming, it also brought the additional cost. So how to use the proxy pattern properly is a constant question.