Small knowledge, big challenge! This article is participating in the creation activity of “Essential Tips for Programmers”.

A proxy mode

1.1 introduction

Java dynamic proxies are used in a wide range of scenarios in practice, such as Spring AOP in the most scenarios, Java annotation fetching, logging, user authentication, and so on.

First look at the definition of Baidu Encyclopedia:

Definition of proxy pattern: Provides a proxy for other objects to control access to that object. In some cases, an object is inappropriate or cannot directly reference another object, and a proxy object can act as an intermediary between the client and the target object.Copy the code

The Proxy pattern is interpreted as setting up a specified “Proxy class” to execute specific methods in the RealSubject class. The left and right operations in the RealSubject class are performed by invoking the RealSubject class through the Proxy Proxy class.

With the proxy model, we can do two things:

  1. Hide the concrete implementation of the proxy class (the real implementation is in the RealSubject class).

  2. Decoupling the client from the proxy class allows you to add some additional functionality (logging, permissions), and so on, without changing the proxy class code.

1.2 Proxy Mode Role Definition

In the above process, we can define three types of objects in the programming process:

  • Subject (Abstract topic role) : Typically an interface that defines the public external methods of the proxy class and the real topic, as well as the methods used by the proxy class to proxy the real topic. For example: selling goods and so on.
  • RealSubject (RealSubject role) : class that actually implements the business logic. For example, a Factoryer implements methods such as advertising and selling.
  • Proxy (Proxy topic role) : Used to Proxy and encapsulate real topics. For example, timeout (Shop) also implements advertising, selling, and so on.

The class diagram corresponding to the above three roles is as follows:

Ii. Static Proxy

2.1 Introduction and Examples

A static proxy is a proxy class that exists before the program runs. In this case, the proxy class is usually defined in Java code.

Static agent example: The main function of the IFactory that a Factoryer needs to perform is the sell method of the factory. We now need to entrust the agent shop to sell the goods. A customer, or client, buys things through an agent called shop.

The IFactory interface is defined as follows:

The /** ** Subject interface * IFactory defines what to do, which is to sell something, but the factory is delegated to the store. The delegate and proxy classes implement the IFactory interface **/
   public interface IFactory { 
   / * * sale * /
   void sell(a);

}
Copy the code

The Vendor class is defined as follows

/** * RealSubject class * RealSubject class, which is the body of the real implementation method that the client calls indirectly through the proxy class. * The Factory owner, who wants to sell things, is the concrete realization of the abstract subject Factory, who wants to sell things **/
   public class Factoryer implements IFactory{

   @Override
   public void sell(a) {
       System.out.println("Sale of goods"); }}Copy the code

The Shop class is defined as follows:

/** * Proxy **/
public class Shop implements IFactory{
 
    private Factoryer factoryer;
 
    public Shop(Factoryer factoryer){
        this.factoryer = factoryer;
    }
 
    @Override
    public void sell(a) {
        System.out.println("Shop is a Shop agent that connects directly to client customers and executes the sell method."); factoryer.sell(); }}Copy the code

The proxy class Shop holds the reference of the proxy class Factoryer through aggregation, and invokes the corresponding method of Factoryer in the corresponding method.

Let’s take a look at how the proxy class is used on the client side, that is, how the customer buys things through the proxy system.

public class ClientBuy {
 
    public static void main(String[] args) {
 
        // Proxy class
        Factoryer factoryer = new Factoryer();
 
        // Create the vendor's proxy class Shop (that is, the factoryer that actually performs the sell method)
        IFactoryer ifactoryer = new Shop(factoryer);
 
        // The customer is facing the agent class Shop.ifactoryer.sell(); }}Copy the code

In the code above, we can modify or add something to Shop without affecting the propped class Factoryer. For example, we can add some additional processing in the Shop class, such as filtering purchasing users, logging, and so on.

2.2 Disadvantages of static proxies

Static proxies are simple to implement and do not invade the original code, but when the scenario is complex, static proxies have the following disadvantages:

1. When you need to delegate multiple classes, the proxy object implements the same interface as the target object. We have only two options: 1. Maintain only one proxy class to implement multiple interfaces, but this will cause the proxy class to become too large; 2: Create multiple proxy classes, but this will generate too many proxy classes.

2. When an IFactoryer needs to add, delete, or modify methods, both the target object (ClientBuy) and the proxy class (Shop) need to be modified at the same time, making it difficult to maintain.

This is where dynamic proxies come in.

Three dynamic proxy

A dynamic proxy is a proxy created by a proxy class while the program is running. In this case, the proxy class is not defined in Java code, but is dynamically generated at run time according to “directives” in Java code.

The advantage of dynamic proxy over static proxy is that it is easy to uniformly handle the functions of the proxy class without modifying the functions of each proxy class.

3.1 Based on JDK native dynamic proxy implementation

Dynamic proxies are typically implemented in two ways: JDK native dynamic proxies and CGLIB dynamic proxies. Here, we use JDK native dynamic proxy as an example to explain.

The JDK dynamic Proxy involves two main categories: Java. Lang. Reflect. The Proxy and Java lang. Reflect. InvocationHandler.

The InvocationHandler interface defines the following methods:

/** * calls the handler */
public interface InvocationHandler { 
    Object invoke(Object proxy, Method method, Object[] args); 
}
Copy the code

As the name implies, the mediation class that implements this interface is used as an “invocation handler.” When a method of a proxy class object is called, this “call” is forwarded to the Invoke method. In a dynamic Proxy, the Proxy dynamically generates a Proxy that calls the InvocationHandler implementation class, so the InvocationHandler is the actual executor.

In the InvocationHandler method, the first parameter proxy is the object of the proxy class, the second parameter method is the method of the proxy class, and the third parameter args is the method parameter of the second parameter.

Calls to all methods in the proxy class then become calls to Invoke, and uniform processing logic can be added to invoke methods (or different processing can be done to different proxy class methods based on the Method argument).

Let’s use adding logs as an example to demonstrate dynamic proxies.

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Date;
 
public class LogHandler implements InvocationHandler {
    Object target;  // The proxied object, the actual method executor
 
    public LogHandler(Object target) {
        this.target = target;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        before();
        Object result = method.invoke(target, args);  // Call target's method method
        after();
        return result;  // Returns the execution result of the method
    }
    // Execute before invoking the invoke method
    private void before(a) {
        System.out.println("Log handling before calling the method sell");
    }
    // Execute after invoking the invoke method
    private void after(a) {
        System.out.println("Log handling after calling the method sell"); }}Copy the code

The client writes the program using dynamic proxy code as follows:

import java.lang.reflect.Proxy;
/** * Dynamic proxy test **@author sec
 * @version 1.0
 * @date 2020/3/21 10:40 AM
 **/
public class DynamicClientBuy {
    public static void main(String[] args) {
 
        // Create a mediation class instance
        LogHandler logHandler = new LogHandler(new Factoryer());
 
        // Get the proxy class instance IFactory
        IFactory iFactory = (IFactory) (Proxy.newProxyInstance(
                                            IFactory.class.getClassLoader(), 
                                            new Class[]{IFactory.class}, 
                                            logHandler)
                                        );
 
        // Calling a proxy class method from a proxy class object actually goes to the invoke method calliFactory.sell(); }}Copy the code

The meanings of the three parameters of roxy.newProxyInstance are as follows:

  • Loader is naturally a class loader
  • Interfaces that the interfaces code will use to proxy
  • H An InvocationHandler object

After the command is executed, the following logs are displayed:

Log processing before calling the sell method Shop Sell goods Log processing after calling the sell methodCopy the code

After the above verification, we found that we had successfully added logging to our proxied classes uniformly before and after method execution.

Four summary

Understanding the proxy pattern allows us to design systems that are more scalable. Dynamic proxy is more widely used in all kinds of frameworks and business scenarios.

Java dynamic proxies have the advantage of non-invasive code extensions, that is, method enhancements: enrich the method without changing it; You can enhance some methods without modifying the source code; You can do whatever you want before or after a method (even without executing the method). Old functionality is not a problem with the old approach, and new functionality is enriched by proxies and can be widely tried out.

Dynamic proxy classes: Dynamically generated by reflection while the program is running. Dynamic proxy classes typically proxy all classes under an interface. Dynamic proxies do not know in advance what is being proxied, only at run time. A dynamic Proxy InvocationHandler must first InvocationHandler interface and dynamically create the Proxy class using the newProxyInstance method in the Proxy class. Java dynamic proxy can only proxy interfaces. To proxy classes, you need to use third-party libraries such as CGLIB

That’s about it. For more examples, including some analysis of the source code, see my reference article.

Reference:

www.choupangxia.com/2020/03/21/…

Blog.csdn.net/lovejj1994/…

Blog.csdn.net/yaomingyang…

Blog.csdn.net/u011784767/…

Blog.csdn.net/briblue/art… ———————————————— Copyright notice: This article is an original article BY CSDN blogger “Xu Jinjin”. It follows CC 4.0 BY-SA copyright agreement. Please attach the link of the original source and this statement. The original link: blog.csdn.net/LucasXu01/a…