Proxy mode proxy

I. overview

As the name suggests, the business should only focus on the business itself. Transactions outside the job should not be handled by the business itself. The proxy mode is to allow the proxy object to help complete things that should not be handled by the business itself through the addition of the proxy object;

Proxy pattern and Decorator Pattern: the UML class diagrams of the two are almost the same. The difference is that the proxy pattern emphasizes the control of the proxy object, rather than just decorating the target object and enhancing its original functions;

II. Static proxy

2.1 use examples

package cn.http.test;

/**
 * Human behavior
 *
 * @author:wjm
 * @date:2020/6/29 22:31
 */
public interface Events {
    /**
     * Go to the company every day to sign in
     */
    void sign();
}
package cn.http.test;

/**
 * Real role / represented object: person
 *
 * @author:wjm
 * @date:2020/6/29 22:31
 */
public class People implements Events {
    private String name;

    public People(String name) {
        this.name = name;
    }

    @Override
    public void sign() {
        System.out.println("Company sign in succeeded!");
    }
}
package cn.http.test;

/**
 * Bus agent class: it can help real characters complete some behaviors
 *
 * @author:wjm
 * @date:2020/6/29 22:34
 */
public class BusProxy implements Events {
    /**
     * The proxy needs to hold a reference to the proxy object
     */
    private People people;

    /**
     * Creating proxy objects also creates proxied objects
     */
    public BusProxy() {
        this.people = new People("Xiao Ming");
    }

    /**
     * The proxy object and the proxy object implement the same interface< P>
     * The proxy object implements the interface method. First, add the proxy behavior, and then call the interface method implementation of the proxy object
     */
    @Override
    public void sign() {
        System.out.println("Take the bus...");
        people.sign();
    }
}
package cn.http.test;

/**
 * application
 *
 * @author:wjm
 * @date:2020/6/29 22:37
 */
public class Test{
    public static void main(String[] args) {
        //Create a proxy class directly, and the proxy completes the behavior of the proxy object
        Events busProxy = new BusProxy();
        busProxy.sign();
    }
}

The above is an example of static proxy. Static proxy is only applicable to one proxy object representing one proxy object. For example, in the example, a person needs to go to the company to sign in and proxy a person through a bus;

If there are multiple proxied objects, and the behaviors of the proxied objects are different, then the static proxy is used. The "proxy object" needs to implement all the interfaces implemented by the "proxy object", and the proxy object needs to be modified every time a proxy object is added, which violates the opening and closing principle of the design pattern (open to extension and close to modification) - > dynamic proxy emerges as the times require;

Three dynamic proxies DynamicProxy

3.1 use examples

The behavior interface of two real characters and two real characters;

package cn.http.test;

/**
 * Intranet
 *
 * @author:wjm
 * @date:2020/6/29 23:14
 */
public interface Intranet {
    /**
     * Connect to Intranet
     */
    void intranetConnect(String intranetUrl);
}
package cn.http.test;

/**
 * Extranet
 *
 * @author:wjm
 * @date:2020/6/29 23:14
 */
public interface Extranet {
    /**
     * Connect to the Internet
     */
    void extranetConnect(String extranetUrl);
}
package cn.http.test;

/**
 * Real role / proxy object: optical cat, used for Internet communication
 *
 * @author:wjm
 * @date:2020/6/29 23:19
 */
public class Modem implements Extranet {
    @Override
    public void extranetConnect(String extranetUrl) {
        System.out.println("The optical cat is successfully connected to the Internet, url:" + extranetUrl);
    }
}
package cn.http.test;

/**
 * Real role / proxy object: switch, used for intranet communication
 *
 * @author:wjm
 * @date:2020/6/29 23:21
 */
public class Switch implements Intranet {
    @Override
    public void intranetConnect(String intranetUrl) {
        System.out.println("The switch is successfully connected to the intranet, url:" + intranetUrl);
    }
}

Before the above two real characters have their own behaviors, they want to add some common behaviors, such as keyword filtering. Next, they use dynamic agents to represent multiple real characters and add keyword filtering;

package cn.http.test;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

/**
 * Proxy class: keyword filtering <p>
 * Implement InvocationHandler interface and realize dynamic proxy through reflection
 *
 * @author:wjm
 * @date:2020/6/29 23:25
 */
public class KeywordFilter implements InvocationHandler {

    /**
     * The proxy object does not pay attention to specific types
     */
    private Object proxiedObj;

    /**
     * When initializing the proxy class, inject the proxied object
     *
     * @param proxiedObj
     */
    public KeywordFilter(Object proxiedObj) {
        this.proxiedObj = proxiedObj;
    }

    /**
     * Calling methods of the proxied object through reflection
     *
     * @param proxy  The class of the method to be executed
     * @param method Methods to be performed
     * @param args   Parameter list of the method to be executed
     * @return
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("Keyword filtering...");
        //Pass in proxy object to complete reflection call
        return method.invoke(proxiedObj, args[0]);
    }
}

Application;

package cn.http.test;

import java.lang.reflect.Proxy;

/**
 * application
 *
 * @author:wjm
 * @date:2020/6/29 23:48
 */
public class Test {
    public static void main(String[] args) {
        //Extranet
        Extranet extranet = (Extranet) Proxy.newProxyInstance(
                //Class objects for real characters
                Modem.class.getClassLoader(),
                //Interfaces implemented by real roles
                Modem.class.getInterfaces(),
                //new proxy class object (new proxied class object)
                new KeywordFilter(new Modem())
        );
        extranet.extranetConnect("http://test1.com");

        //Intranet
        Intranet intranet = (Intranet) Proxy.newProxyInstance(
                Switch.class.getClassLoader(),
                Switch.class.getInterfaces(),
                new KeywordFilter(new Switch())
        );
        intranet.intranetConnect("http://test2.com");
    }
}

It can be seen that whether you are accessing the external network or the internal network, you only need to generate and call the corresponding proxy respectively. Before the behavior of the real role is executed, the proxy behavior (filter) will be executed first;

IV. summary

Static and dynamic agents:

  • Static proxy: a proxy class can only proxy one real role (the real role implements the corresponding behavior of its interface). When there are multiple real roles and their proxies have the same behavior, the shortcomings of static proxy are obvious: java supports multiple implementations, but one proxy class can not implement all the interfaces corresponding to the real role;
  • Dynamic proxy: no matter how many real roles there are, you only need to write the common behavior of the proxy class. The proxy class only needs to implement InvocationHandler. When implementing the specific methods of the real role, it is implemented through reflection. Therefore, you can dynamically generate the proxy at runtime, so that it can be compatible with any interface;

Application of dynamic agent:

  • For example, in Aspect oriented AOP of Spring, you only need to define an Aspect class @Aspect and declare its Pointcut @Pointcut (which methods of which objects are proxied correspond to the methods in the "Intranet" and "extranet" interfaces in the above examples), And the code block to be cut in (that is, the behavior of the agent, such as the filtering function of the agent class in the above example, which can be divided into pre execution @Before, post execution @after, exception handling @AfterThrowing, etc.). After configuration, the framework will automatically generate the agent and cut in the target execution;
  • For example, in transaction control, you should first switch to "transaction start" before all business codes, and then switch to "transaction commit" after execution. If thrown exceptions are caught, you should execute "transaction rollback", so it is not necessary to write these duplicate codes in each business class;

Notes sorting source: Technical documentation

Tags: Java Design Pattern

Posted by GreenSmurf on Wed, 01 Jun 2022 20:11:53 +0530