First, the concept of agency

Provide a proxy for an object to control access to that object. Proxy classes and delegate classes have a common parent class or parent interface, so proxy objects can be used wherever delegate objects are used. The proxy class is responsible for pre-processing, filtering, dispatching requests to the delegate class for processing, and subsequent processing after the delegate class executes the request.

Figure 1: Proxy mode

As can be seen from the figure, proxy interface (Subject), proxy class (ProxySubject), and proxy class (RealSubject) form a “product” structure.

Agents can be divided into static agents and dynamic agents according to their generation time.

Static and dynamic proxies are illustrated with a mock requirement: the delegate class handles a long task, and the client class prints out the time spent performing the task. To solve this problem, record the time before and after the task execution. The time difference is the time consumed by the task execution

Static proxy

By our own creation or tool generation proxy class source, and then compile proxy class. Static means that the bytecode file of the proxy class exists before the program runs, and the relationship between the proxy class and the delegate class is determined before the program runs

1: indicates the proxy interface

/** *  The proxy class implements the proxy interface. */ public class ProxySubject implements Subject {// Private Subject implements Subject; public ProxySubject(Subject delegate) { this.delegate = delegate; } /** * assign the request to the delegate class, record the time before and after the task is executed, * * @param taskName */ @override public void dealTask(String taskName) {long stime = System.currentTimeMillis(); // Assign the request to the delegate class to handle delegate.dealTask(taskName); long ftime = System.currentTimeMillis(); System.out.println("Task Execution Time"+(ftime - stime)+"毫秒"); }}Copy the code

Listing 3: Static proxy class

Public Class SubjectStaticFactory {// The client class calls this factory method to get the proxy object. // The client class does not know whether it is returning a proxy or delegate object. public static SubjectgetInstance() {returnnew ProxySubject(new RealSubject()); }}Copy the code

Listing 4: Generate a static proxy class factory

Public Class SubjectStaticFactory {// The client class calls this factory method to get the proxy object. // The client class does not know whether it is returning a proxy or delegate object. public static SubjectgetInstance() {returnnew ProxySubject(new RealSubject()); }}Copy the code

Listing 5: Customer class

public class Client1 {  

 public static void main(String[] args) {  
  Subject proxy = SubjectStaticFactory.getInstance();  
  proxy.dealTask("DBQueryTask"); }}Copy the code

Advantages and disadvantages of static proxy classes

Advantages: The business class only needs to focus on the business logic itself, which ensures the reuse of the business class. This is the common advantage of agency. Disadvantages: 1) An interface of a proxy object only serves one type of object. If there are many methods to be propped up, it is necessary to propped up for each method. 2) If an interface adds a method, all proxy classes need to implement the method in addition to all implementation classes. Increases the complexity of code maintenance.

Dynamic proxy

The source code for the dynamic proxy class is generated dynamically by the JVM during program execution, based on mechanisms such as reflection, so there are no bytecode files for the proxy class. The relationship between the proxy class and the delegate class is determined at runtime.

1. Take a look at the Java API closely associated with dynamic proxies. 1) Java.lang.Reflect.proxy this is the parent class of all dynamic Proxy classes generated by the Java dynamic Proxy mechanism. It provides a set of static methods to dynamically generate Proxy classes and their objects for a set of interfaces.

Static methods of the Proxy class

/ / method 1: Static InvocationHandler getInvocationHandler(Object Proxy) static InvocationHandler getInvocationHandler(Object Proxy) Static Class getProxyClass(ClassLoader loader, Class[] interfaces) // Static Class getProxyClass(ClassLoader, Class[] interfaces) Static Boolean isProxyClass(Class cl) static Boolean isProxyClass(Class CL) Static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)Copy the code

Java. Lang. Reflect InvocationHandler this is called the processor interface, since it defines an invoke method, used to deal with the focus on the dynamic proxy class object method calls, usually in the method of the class of agents. A corresponding invocation handler object is specified each time a dynamic proxy class object is generated.

Listing 7: The core method of InvocationHandler

// This method is responsible for centrally handling all method calls on a dynamic proxy class. The first argument is both an instance of the proxy class, and the second argument is the method object being called // and the third method is the call argument. Object Invoke (Object Proxy, Method Method, Object[] args)Copy the code

java.lang.ClassLoader

The specific steps are as follows: a. Implement the InvocationHandler interface to create your own call handler b. Provide the Proxy class with a ClassLoader and an array of Proxy interface types. Taking the calling processor type as parameter, the constructor of dynamic proxy class d. A dynamic proxy class object is created using the constructor of the dynamic proxy class, taking the call processor object as an argument

Listing 8: Implement the dynamic proxy step by step

// InvocationHandlerImpl implements the InvocationHandler interface and can dispatch method calls from the proxy class to the delegate class. InvocationHandler handler = new InvocationHandlerImpl(..) ; Class clazz = proxy.getProxyClass (classLoader); new Class[] { Interface.class, ... }); Constructor = clazz.getconstructor (new Class[] {invocationHandler.class}); Interface Proxy = (Interface) constructor.newinstance (new Object[] {handler});Copy the code

The static method newProxyInstance of Proxy class encapsulates the last three steps of the above steps, simplifying the process of obtaining dynamic Proxy objects.

Listing 9: Example dynamic proxy implementation

// Public Class SubjectInvocationHandler implements InvocationHandler {// The proxy class holds a delegate class's object reference private Object delegate; public SubjectInvocationHandler(Object delegate) { this.delegate = delegate; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { long stime = System.currentTimeMillis(); // Use reflection to assign the request to the delegate class. Method's invoke returns an Object as the result of Method execution. // Because the sample program does not return a value, method.invoke(delegate, args) is ignored here; long ftime = System.currentTimeMillis(); System.out.println("Task Execution Time"+(ftime - stime)+"毫秒");  

  returnnull; }}Copy the code

Dynamic proxy mechanism features

First, there are some characteristics of the dynamically generated proxy classes themselves. 1) the package: If the propped interface is all public, it will be defined in the top-level package (i.e., the package path is empty). If the propped interface has non-public interfaces (since interfaces cannot be defined as protect or private, So it is the default package access level except public), then it will be defined in the package where the interface is (assuming that some non-public interface A in the com.ibm. developerWorks package is brokered, The package in which the newly generated proxy class resides is com.ibm.developerWorks). This is designed to ensure that the dynamic proxy class cannot be successfully defined and accessed due to package management problems.

2) Class modifiers: This proxy class has final and public modifiers, meaning that it can be accessed by all classes, but cannot be inherited again;

3) Class name: The format is “$ProxyN”, where N is an incrementing Arabic number representing the NTH dynamic Proxy class generated by Proxy. Note that N does not increase with each call to Proxy’s static method to create a dynamic Proxy class. Reason is that if the same set of interfaces (including interface are arranged in the order of the same) tries to create the dynamic proxy classes, it will return to a previously created wisely good proxy class class object, rather than to try to create a new proxy classes, that can save unnecessary code duplication, improve the efficiency of the proxy class to create.

4) Class inheritance relationship: The inheritance relationship of this class is shown as follows:

As you can see from the figure, Proxy class is its parent, and this rule applies to all dynamic Proxy classes created by Proxy. This class also implements the set of interfaces it proides, which is the root reason why it can be safely typed to one of the interfaces it proides.

Let’s look at some of the characteristics of proxy class instances. Each instance is associated with a call handler object, which can be obtained through the static method getInvocationHandler provided by Proxy. When a proxy class instance calls a method declared in its proxy interface, these methods are eventually executed by the invoking processor’s Invoke method. In addition, it is worth noting that three methods in the root java.lang.Object class of the proxy class are also dispatched to the invoking processor’s Invoke method. They are hashCode, Equals, and toString for several possible reasons. First, these methods are public and non-final, and can be overridden by a proxy class. Secondly, these methods usually present some characteristic attributes of a class and have certain degree of differentiation. Therefore, in order to ensure the external consistency of the proxy class and the delegate class, these three methods should also be assigned to the delegate class for execution. When a group of interface agent has repeatedly promised method and this method is invoked, the proxy class always derive from the top interface method object is assigned to call processor, and no matter whether the proxy class instances in the interface (or a child of the inheritance in the interface interface) is in the form of external references, because inside the proxy class cannot distinguish between its current reference types.

Next, look at the characteristics of a proxied set of interfaces. First, be careful not to have duplicate interfaces to avoid compilation errors when generating dynamic proxy class code. Second, these interfaces must be visible to the class loader, otherwise the class loader will not be able to link them and the class definition will fail. Again, all non-public interfaces to be proxied must be in the same package, otherwise proxy class generation will also fail. Finally, the number of interfaces cannot exceed 65535, which is the limit set by the JVM.

Finally, take a look at the characteristics of exception handling. You can see from the method that calls the processor interface declaration that it can theoretically throw any type of exception, because all exceptions inherit from the Throwable interface, but is that true? The answer is no, because we must observe an inheritance principle: when a subclass overrides a parent class or implements a parent interface method, the exception thrown must be in the list of exceptions supported by the original method. So while calling the handler is theoretically possible, in practice it is often limited unless methods in the parent interface support Throwable exceptions. So what if an Invoke method does raise an exception that is not supported in the interface method declaration? Rest assured, Java dynamic proxy classes have designed a solution for us: it will be thrown UndeclaredThrowableException anomalies. This exception is of type RuntimeException, so it does not cause a compilation error. With the exception’s getCause method, you can also get the original unsupported exception object for error diagnosis.

5. Advantages and disadvantages of dynamic proxy

Advantages:

The biggest advantage of dynamic proxies compared to static proxies is that all methods declared in the interface are moved to a centralized method of the calling handler (InvocationHandler.invoke). In this way, when the number of interface methods is large, we can do flexible processing without the need for each method to be mediated like a static proxy. You can’t see it in this example, because the Invoke method has concrete peripheral business embedded inside it (logging the time before and after the task is processed and calculating the time difference), which could be similar in practice

Fly in the ointment:

Yes, Proxy has been beautifully designed, but there is a small regret that it has never been able to escape the shackles of interface Proxy only because it was designed to do so. Recall the inheritance diagram for dynamically generated Proxy classes that are destined to have a common parent class called Proxy. Java’s inheritance mechanism prevents these dynamic proxy classes from implementing dynamic proxies to classes because multiple inheritance is inherently unworkable in Java.

There are many reasons why one can deny the need for a class proxy, but there are also some reasons why supporting a class dynamic proxy would be better. The division of interfaces and classes was not obvious until Java became so detailed. If you look at methods only in terms of how they are declared and whether they are defined, there is a hybrid called abstract class. Implementing dynamic proxies for abstract classes also has inherent value. In addition, there are legacy classes that will never be used for dynamic proxies because they do not implement any interfaces. Such a variety, have to say is a small regret.

Read more

Job-hopping is ok, but keep your posture correct!

Pros and cons of React – Native technology

Golden three silver four job-hopping season, Ali interview just back summary – dry goods!

Believe in yourself, there is nothing impossible, only unexpected

Wechat official account: Terminal R&D Department