proxy pattern
proxy mode is to provide a proxy class for a real class. The proxy class completes its functions instead of the real class. Generally, some additional functions that the real class does not have can be added to the proxy class. Generally speaking, the proxy mode is a common intermediary in our life, and the proxy mode can be divided into static agent and dynamic agent.
Static proxy
static proxy requires the proxy class and the target class to implement the same interface. Generally, the proxy object is combined into the proxy class, and then it is used to complete the corresponding functions, and additional functions can be added to the proxy class.
Rental static agent process
Step 1: create a service interface
public interface Rent { // Rental housing void rent(); }
Step 2: the implementation class implements the service interface
public class Host implements Rent{ @Override public void rent() { System.out.println("The landlord wants to rent the house..."); } }
Step 3: the proxy class implements the service interface
public class Proxy implements Rent{ // The proxy class is used to complete the functions of the proxy class. private Host host; // Used to initialize the proxied class public void setHost(Host host) { this.host = host; } // Complete the functions of the proxy class, and other functions can be added at the same time. @Override public void rent() { doSomething(); host.rent(); doSomething(); } // Additional features private void doSomething() { System.out.println("doSomething..."); } }
Step 4: write a test class
public class Test { public static void main(String[] args) { Host host = new Host(); Proxy proxy = new Proxy(); proxy.setHost(host); proxy.rent(); } }
Static agent summary
advantage
- High extensibility: you can extend the function of the target class without modifying the target class.
shortcoming
- Redundancy: a target class will generate a proxy class, which will generate too many proxy classes.
- Low development efficiency: the amount of agent code is heavy.
- Difficult to maintain: once the interface is changed, both the target class and the proxy class must be modified.
Dynamic agent
in dynamic proxy, we don't need to create proxy classes manually. We just need to write a dynamic processor to dynamically create proxy objects for us. The proxy objects are dynamically created by JDK at runtime, and the dynamic proxy is implemented based on reflection.
Common dynamic proxy methods
- Interface based dynamic Proxy: provided by JDK, the Proxy object is created using the official Proxy class of JDK.
- Class based dynamic proxy: provided by the third party CGLib, the proxy object is created using the Enhancer class of CGLib
- javassist
- ......
Interface based dynamic agent
to use interface based dynamic Proxy, you first need to understand the Proxy class and InvocationHandler interface in JDK, and then use them to write a dynamic processor to complete the dynamic Proxy.
Proxy class
Proxy provides static methods for creating dynamic Proxy classes and instances. It is also a superclass of all dynamic Proxy classes created by these methods.
generally, Proxy classes are created using the newProxyInstance static method of Proxy. A class loader, a service interface of the Proxy class, and an InvocationHandler object need to be provided.
- Class loader: used to load classes and interfaces
- Proxy class interface: provides proxy class service interface information
- InvocationHandler object: the method used to execute the proxied class
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h);
InvocationHandler interface
When calling methods on proxy instances, the method calls are encoding and assigned to the calling method of their calling handlers, that is, when the method is invoked in Proxy, the method calls are assigned to the invoke method executed in the InvocationHandler object, and the invoke method is called to execute the method of the proxy object.
Object invoke(Object proxy, Method method, Object[] args);
Dynamic processor utility class
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class ProxyInvocationHandler implements InvocationHandler { // Proxy interface private Object target; public ProxyInvocationHandler() { } public ProxyInvocationHandler(Object target) { this.target = target; } // Used to initialize the proxied class public void setTarget(Object target) { this.target = target; } // Generated proxy class public Object getProxy() { return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(), this); } // Process proxy samples and return results @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { return method.invoke(target, args); } }
Dynamic agent process of renting house based on interface
Step 1: create a service interface
public interface Rent { // Rental housing void rent(); }
Step 2: the implementation class implements the service interface
public class Host implements Rent{ @Override public void rent() { System.out.println("The landlord wants to rent the house..."); } }
Step 3: write a dynamic processor
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class ProxyInvocationHandler implements InvocationHandler { // Proxy interface private Object target; // Used to initialize the proxied class public void setTarget(Object target) { this.target = target; } // Generated proxy class public Object getProxy() { return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(), this); } // Process proxy samples and return results @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { doSomething(); Object invoke = method.invoke(target, args); doSomething(); return invoke; } // Additional features private void doSomething() { System.out.println("doSomething..."); } }
Step 4: write a test class
public class Test { public static void main(String[] args) { Host host = new Host(); ProxyInvocationHandler proxyInvocationHandler = new ProxyInvocationHandler(); proxyInvocationHandler.setTarget(host); Rent proxy = (Rent)proxyInvocationHandler.getProxy(); proxy.rent(); } }
Dynamic agent summary
advantage
- High extensibility: you can extend the function of the target class without modifying the target class.
- Low redundancy: too many proxy classes will be generated.
- Low coupling: reduce the dependence on business interfaces.
- Efficient development: greatly reduce development tasks, and a dynamic processor can complete the agent.
matters needing attention
- Due to the addition of proxy objects between the client and the real topic, some types of proxy patterns may slow down the processing of requests.
- Implementing the proxy pattern requires additional work, and the implementation of some proxy patterns is very complex.
- Difference between adapter mode and adapter mode: adapter mode mainly changes the interface of the considered object, while proxy mode cannot change the interface of the proxy class.
- The difference between decorator mode and decorator mode: decorator mode is for enhancement, while agent mode is for control.