This article has participated in the good article call order activity, click to see: back end, big front end double track submission, 20,000 yuan prize pool for you to challenge!

Introduction to the Proxy Pattern

Examples from life

What is agency? An agent is an intermediary, if there is a university, recruiting students from all over the world. But the student pool is so wide that it can only be entrusted to recruitment agents to help the university recruit students. The intermediary is the school’s agent, the intermediary completes the enrollment function instead of the university.

This agent has the following characteristics:

  • Agents do the same thing as schools, they recruit students
  • The intermediary is the agent of the school, and the school is the ultimate goal of the students
  • The intermediary takes the place of the school to introduce students to the school and handle the admission procedures
  • The intermediary can’t work for nothing, and it needs to charge a certain fee (function enhancement)
  • The intermediary isolates the school from the students, denying the students direct access to the school (controlled access).

Why use an agent?

  • The intermediary is professional and can reduce a lot of unnecessary trouble
  • Students do not have the ability to directly visit the school, or the school does not accept direct visits from students

Example under development

This is a real life example, and we will have similar situations in our development.

There is A class A that needs to call A method of class C, but C won’t let class A call it, but let class B access it. So class B becomes the proxy between A and C, with A accessing B, and through B accessing the methods of class C.

Another example is SMS verification code. China Mobile, Unicom and Telecom have the ability to send SMS, but we cannot call their interfaces directly in the development. We need to call through their associated subsidiaries, which are responsible for providing the functional interfaces for sending SMS to the society. The call chain is as follows: item A calls –> the public interface of the subsidiary or affiliate company –> calls the real interface of mobile/Unicom/Telecom. These subsidiaries act as mediations in the schooling instance, and the actual interface that is invoked is our target, the college in the schooling example.

What’s the good

  • Function enhancement: On the basis of the original, to add additional functions, such as agent is to charge, collect the fee to help you deal with procedures (this is not a good thing ah QAQ), the charge is the new function.
  • Control access: Proxy classes do not allow you direct access to the target class, for example, vendors do not allow users direct access to the vendor, which is also more secure.

Static proxy:

The proxy class is manually implemented to create a Java class that represents the proxy class, and the target class that you proxy is determined.

The implementation process

Static proxy implementation is relatively simple, simple to say the general steps.

  1. Create an interface that defines the target-related methods that represent the functionality that the target class will implement
public interface StudyInterface {
	void study();
}
Copy the code
  1. Create a target class that implements the interface in 1
public class RealSchool implements StudyInterface { @Override public void study() { System.out.println("real study"); }}Copy the code
  1. Create a proxy class that also implements the interface in 1
Public class ProxySchool implements StudyInterface{// implements a reference to the target class RealSchool RealSchool; public ProxySchool(RealSchool realSchool) { this.realSchool = realSchool; } @override public void study() {doSomethingBefore(); // The target class calls realschool.study (); // doSomethingAfter(); } public void doSomethingBefore() { System.out.println("before"); } public void doSomethingAfter() { System.out.println("before"); }}Copy the code
  1. Create a client class to invoke through the proxy
Public class Test {public static void main(String[] args) {ProxySchool school = new ProxySchool(new) RealSchool()); // Call school.study() through the proxy class; }}Copy the code

defects

Static proxies can be designed in just a few short steps. Because their types are defined, that is, the.class file exists before the program runs, they run efficiently, and we can extend them by adding the functionality we need when we use them.

But it also has very obvious flaws, the proxy class and target class needs to implement the same interface, so there is a lot of duplicate code, if the interface or change a way to increase a method, in addition to all of the target class need to modify, all of the proxy class also needs to be modified, it is intuitive increased the difficulty of maintenance, second, Proxy objects can only serve one type of target class. If you want to serve multiple types of target classes, you need to create a responsive proxy object for each type of target. If you are a large project, the trouble of using a static proxy is multiplied.

Dynamic proxy:

With static proxies out of the way and the disadvantages of static proxies out of the way, it’s time to look at dynamic proxies and how they can be circumvented.

What is dynamic proxy? During the execution of the program, use the JDK’s reflection mechanism to create a proxy class object and dynamically specify the target class to proxy. That is, dynamic proxy is the ability to create Java objects.

Implementation of dynamic proxy: Use the classes and interfaces in the Java reflection package to implement the function of dynamic proxy. There are three important classes:

InvocationHandler

Invoke () is an interface that has only one invoke () method. This method represents the function code that the proxy object performs. The function that the proxy class performs is written in this method. What does the proxy class do?

  1. Call target method
  2. Functionality enhancements that add functionality while calling target methods
public interface InvocationHandler {
    public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;
}
Copy the code

This method takes three arguments:

  1. Object proxy: A proxy Object created by JDK. No value is required
  2. Method Method: Method in the target class. JKD provides Method objects
  3. Object[] args: An argument to a method in the target class, also provided by the JDK

InvocationHandler says what does our agent do and how does it work?

  1. Create a class to implement the InvocationHandler interface
  2. Override the invokeP() method to put in the function that was originally implemented in the static proxy.

Method

Represents a method, specifically a method in the target class. Method. Invoke (object, Method parameter)

Proxy

Create a proxy object using the Porxy class method newProxyInstance().

public static Object newProxyInstance(ClassLoader loader, Class<? >[] interfaces, InvocationHandler h) throws IllegalArgumentException { ... }Copy the code

Take a look at its three parameters:

  1. ClassLoader: ClassLoader that is responsible for loading objects into memory and using reflection to get the objects.A.getClass().getClassLoader()To get the class loader for the target object
  2. Class
    [] interfaces: an interface implemented by the target object
  3. InvocationHandler H: Our own InvocationHandler, representing the agent class to accomplish the function

Implement a dynamic proxy

  1. Create an interface that defines what the target class does
Public interface StudyInterface {void study(); public interface StudyInterface {void study(); }Copy the code
  1. Create the target class to implement the interface
Public class RealSchool implements StudyInterface{@override public void study() {system.out.println ("real school"); }}Copy the code
  1. Create an implementation class of the InvocationHandler interface to perform the specified function in the Invoke method
public class MyInvocationHandler implements InvocationHandler { private Object obj; Public MyInvocationHandler(Object obj) {this.obj = obj; this.obj = obj; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {system.out.println ("study before"); Object invoke = method.invoke(obj, args); System.out.println("study after"); Return invoke; }}Copy the code
  1. Using the static methods of the Proxy class, create the Proxy object and convert the return value to the interface type
Public static void main(String[] args) {// Create the target object StudyInterface Study = new RealSchool(); / / create InvocationHandlerduixiang MyInvocationHandler handler = new MyInvocationHandler (study); StudyInterface newProxyInstance = (StudyInterface) proxy.newProxyInstance (study.getClass().getClassLoader(), study.getClass().getInterfaces() , handler); //com.sun.proxy.$Proxy0 System.out.println(newProxyInstance.getClass().getName()); // Call the method newProxyInstance.study() through the proxy object; }Copy the code

Principles of dynamic proxy

System.out.println(newProxyInstance.getClass().getName());
Copy the code

In the above code we print the name of the newProxyInstance proxy class: com.sun.proxy.$Proxy0. So what is Proxy0?

public final class $Proxy0 extends Proxy implements StudyInterface { private static Method m1; private static Method m2; private static Method m3; private static Method m0; ** super(paramInvocationHandler) is the constructor that calls the superclass Proxy. * Parent class holds: protected InvocationHandler h; */ public $Proxy0(InvocationHandler paramInvocationHandler) throws { super(paramInvocationHandler); } static {...} static {...} static {... // See what's inside the static block and see if you find the study method. M3 m1 = class.forname (" java.lang.object ").getMethod("equals"), new Class[] { Class.forName("java.lang.Object") }); m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]); m3 = Class.forName("proxy.StudyInterface").getMethod("study", new Class[0]); m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]); return; . } /** ** here, we call the invoke method of the InvocationHandler, and pass m3 into it. * this.h.invoke(this, m3, null) */ public final void study() { ... this.h.invoke(this, m3, null); return; . }}Copy the code

The JDK generates a proxy0 for us (0 is the number, and if there are multiple proxy classes, the class file is in memory). When we create a proxy object, we use reflection to get the constructor of this class and then create an instance of the proxy.

We can think of The InvocationHandler as a mediation class that holds a proscribed object (the target object we pass in) whose corresponding methods are invoked in the Invoke method. The aggregate holds references to the proxied object, turning all external calls to Invoke into calls to the proxied object

When the proxy class invokes its own method, it invokes the Invoke method of the mediation object through the mediation object it holds. In this way, the proxy executes the method of the proxy object. That is, the dynamic proxy implements the concrete proxy functionality through the mediation class.

Calling process

Dynamic proxy question and answer

  • Dynamic proxy Where is the dynamic

A dynamic proxy is called dynamic because its classes are created at runtime. When the code starts executing, there’s no Proxy class, it’s created as needed, from the set of interfaces that you pass in.

  • How do I know if a class is a proxy class?

The static method isProxyClass returns true, indicating that it is a dynamic proxy class.

boolean proxyClass = Proxy.isProxyClass(handler.getClass());
Copy the code
  • Are there any restrictions on the type of interface I can pass newProxyInstance()?

First, we need to pass newProxyInstance an array of interfaces that can only have interfaces, not classes. If the interface is not public, it must belong to the same package. Different interfaces cannot have methods with the same names and parameters.

  • What’s the difference between agent and decorator patterns

In simple terms, decorator mode adds behavior to an object, which is a wrapper around the original object, while agents add additional functionality to the original functionality and target protection to avoid unnecessary access.

conclusion

The proxy pattern is a very important and practical design pattern, which is often used in practical work. It helps you extend the target class while controlling access to it. Dynamic proxy avoids many problems of static proxy. While being more flexible, it will not become difficult to manage because of the growing business. In Android development, Retrofit uses dynamic proxy to encapsulate network requests, which is also a very important embodiment of dynamic proxy. Hopefully, this article will give you a clearer understanding of the proxy pattern.

The resources

  • www.cnblogs.com/gonjan-blog…
  • www.zhihu.com/question/20…
  • Head First Design Mode