Proxy pattern of java design pattern

In some cases, customers can't or don't want to visit another object directly. At this time, they need to find an intermediary to help them complete a certain task. This intermediary is the agent object. For example, renting a house, not necessarily looking for a spot house directly, you can find intermediary help, you can find a job through a headhunter and so on.

Definition and Characteristics of Agent Model

Definition of proxy pattern: For some reasons, it is necessary to provide a proxy for an object to control its access. At this time, the access object is not suitable or can not directly refer to the target object. The proxy object acts as the intermediary between the access object and the target object.

The main advantages of the agent model are as follows:

  • The proxy mode plays an intermediary role between the client and the target object and protects the target object.
  • Proxy object can expand the function of target object
  • The proxy mode can separate the client from the target object and reduce the coupling degree of the system in a certain program.

Its main shortcomings are:

  • Adding a proxy object between the client and the target object can slow down request processing
  • Increased system complexity

Static proxy

Structure of static proxy mode

The structure of proxy mode is relatively simple, which includes real topics by defining an agent inheriting Abstract topics, thus realizing access to real topics.

The main roles of the proxy model are as follows:

  1. Abstract subject roles: Business methods implemented by declaring real topics and proxy objects through interfaces or abstract classes.
  2. Real subject role: also known as the delegated role, the proxy role, realizes the specific business in the abstract theme, is the real object represented by the proxy object, is the ultimate reference object.
  3. Proxy role: Provides the same interface as the real theme, which contains the reference to the real theme. It can access, control and expand the functions of the real theme, and do pre-processing and post-processing before and after the real theme role is processed.

The structure diagram is as follows:

Implementation of static proxy mode

/**
 * Abstract theme
 *
 * @author Jonathan
 * @version 1.0.0
 * @date 2019/8/29 10:07
 * @since 1.0.0+
 */
public interface Subject {
    /**
     * Method to be realized
     */
    void request();
}

/**
 * Real Subject Object
 *
 * @author Jonathan
 * @version 1.0.0
 * @date 2019/8/29 10:08
 * @since 1.0.0+
 */
public class RealSubject implements Subject {

    /**
     * Method to be realized
     */
    @Override
    public void request() {
        System.out.println("Access to Real Topics");
    }
}

/**
 * Proxy object
 *
 * @author Jonathan
 * @version 1.0.0
 * @date 2019/8/29 10:09
 * @since 1.0.0+
 */
public class Proxy implements Subject {

    private RealSubject realSubject;

    /**
     * Method to be realized
     */
    @Override
    public void request() {
        if(realSubject == null) {
            realSubject = new RealSubject();
        }
        preRequest();
        realSubject.request();
        postRequest();
    }

    private void postRequest() {
        System.out.println("Follow-up Processing after Visiting Real Topics");
    }

    private void preRequest() {
        System.out.println("Preprocessing before accessing real topics");
    }

}


/**
 * Client call of static proxy
 *
 * @author Jonathan
 * @version 1.0.0
 * @date 2019/8/29 10:12
 * @since 1.0.0+
 */
public class ProxyClient {
    public static void main(String[] args) {
        Proxy proxy = new Proxy();
        proxy.request();
    }
}

Proxy Schema Extension

General Agent

Ordinary proxy requires clients to be able to access proxy roles on their own and not real roles. That is, they cannot directly access new RealSubject objects. They must be accessed by
The role of proxy carries on. General agent is more common. The above static agent implementation is actually general agent.

Compulsory agency

Our general thinking is to find the real role through the agent model, but to force the agent to do the opposite, we must force the real role to find its agent role.
In a word, mandatory proxy is to create a real role object through new or other means, and the real role object will return its proxy object, and then through proxy.
It's possible to do a series of operations. The most common example in reality is a star and a broker. Well, if you know how a star is connected and find him, he tells you.
Go to my agent XX. He'll take care of it.

The concrete realization is as follows:

/**
 * Abstract theme
 *
 * @author Jonathan
 * @version 1.0.0
 * @date 2019/8/29 10:07
 * @since 1.0.0+
 */
public interface Subject {
    /**
     * Method to be realized
     */
    void request();

    /**
     * Get the corresponding proxy object instance for each specific implementation
     * @return Returns the corresponding proxy object
     */
    Subject getProxy();
}

/**
 * Mandatory Agent Object
 *
 * @author Jonathan
 * @version 1.0.0
 * @date 2019/8/29 14:36
 * @since 1.0.0+
 */
public class ForceProxy implements Subject {

    private Subject subject = null;

    public ForceProxy(Subject subject) {
        this.subject = subject;
    }

    /**
     * Method to be realized
     */
    @Override
    public void request() {
        preRequest();
        this.subject.request();
        postRequest();
    }

    /**
     * @return Returning the corresponding proxy object is itself
     */
    @Override
    public Subject getProxy() {
        return this;
    }

    private void postRequest() {
        System.out.println("Follow-up Processing after Visiting Real Topics");
    }

    private void preRequest() {
        System.out.println("Preprocessing before accessing real topics");
    }
}

/**
 * Specific Implementation Objects
 *
 * @author Jonathan
 * @version 1.0.0
 * @date 2019/8/29 14:35
 * @since 1.0.0+
 */
public class RealSubject implements Subject {

    /**
     * The agent object of the concrete implementation object
     */
    private Subject proxy = null;

    @Override
    public Subject getProxy(){
        this.proxy = new ForceProxy(this);
        return this.proxy;
    }

    /**
     * Method to be realized
     */
    @Override
    public void request() {
        System.out.println("Access to Real Topics");
    }
}


/**
 * Force proxy client invocation
 *
 * @author Jonathan
 * @version 1.0.0
 * @date 2019/8/29 14:40
 * @since 1.0.0+
 */
public class ForceProxyClient {
    public static void main(String[] args) {
        Subject subject = new RealSubject();
        Subject proxy = subject.getProxy();
        proxy.request();
    }
}

Dynamic Agent

What is dynamic proxy? Dynamic proxy does not care who the proxy is in the implementation phase, but which object is designated by JVM in the run phase. Relatively speaking, the way to write proxy classes is static proxy. In dynamic proxy, proxy classes are not defined in java code, but according to what we mean in java code at run time. Represents dynamic generation. Compared with static proxy, the advantage of dynamic proxy is that it can handle the functions of proxy class uniformly without modifying the methods in each proxy class.

There is a noun called Aspect Oriented Programming, whose core is the dynamic proxy mechanism.

JDK Dynamic Agent

Because of the flexible nature of dynamic proxy, we do not need to show its implementation and real Subject when designing dynamic proxy class.
The same interface, but the implementation is deferred to run time.

In order to enable the DynamicProxy class to implement a series of interfaces implemented by the RealSubject class at runtime and perform related method operations in the interfaces,
The dynamicProxy class needs to implement JDK's own java.lang.reflect.InvocationHandler interface, where the invoke() method can
Let DynamicProxy instances call methods in all interfaces that the proxy class needs to implement externally at run time, that is, to complete the call to the real topic class methods.

So we must first load all the interfaces implemented in the real Subject into the JVM, and then we can create one.
An instance of a real topic class is obtained from the class loader ClassLoader of the instance (so-called class loader, even if it has a definition of a class, internal related structures, including inheritance tree, method area, etc.).

There are two important classes and interfaces in java Dynamic Proxy mechanism: InvocationHandler (interface) and Proxy (class). This class Proxy and interface InvocationHandler are the core of our dynamic proxy implementation.

So the steps of JDK dynamic proxy are as follows:

  1. Define an event manager, implement the InvocationHandler interface, and override invoke (proxy class, proxy method, method parameter list)
  2. Implementing specific subject object classes
  3. Invoke Proxy.newProxyInstance (real topic class loader, interface implemented by real topic class, event manager object) to generate a proxy instance.
  4. Call methods through this proxy instance

The concrete realization is as follows:

/**
 * Abstract theme
 *
 * @author Jonathan
 * @version 1.0.0
 * @date 2019/8/29 10:07
 * @since 1.0.0+
 */
public interface Subject {
    /**
     * Method to be realized
     */
    void request();
}

/**
 * Real topic class
 *
 * @author Jonathan
 * @version 1.0.0
 * @date 2019/8/29 11:13
 * @since 1.0.0+
 */
public class RealSubject implements Subject {
    /**
     * Method of concrete realization
     */
    @Override
    public void request() {
        System.out.println("Access to Real Topics");
    }
}

/**
 * Event Manager, Caller of Proxy Class
 *
 * @author Jonathan
 * @version 1.0.0
 * @date 2019/8/29 11:14
 * @since 1.0.0+
 */
public class DynamicProxy implements InvocationHandler {

    /**
     * Real objects in proxy classes
     */
    private Object target;

    /**
     * Constructor
     * @param target Real object
     */
    public DynamicProxy(Object target) {
        super();
        this.target = target;
    }

    /**
     *
     * @param proxy Proxy classes (real proxy objects)
     * @param method Approaches to proxy classes
     * @param args Method parameter list
     * @return Return result of proxy object method or real proxy object (com.sun.proxy.$Proxy0)
     * @throws Throwable Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("before Dynamic Agent");
        method.invoke(target, args);
        System.out.println("after Dynamic Agent");
        return null;
    }
}

/**
 * JDK Dynamic proxy call
 *
 * @author Jonathan
 * @version 1.0.0
 * @date 2019/8/29 11:59
 * @since 1.0.0+
 */
public class DynamicTest {

    public static void main(String[] args) {
        RealSubject realSubject = new RealSubject();
        InvocationHandler dynamicProxy = new DynamicProxy(realSubject);
        Class<?> cls = realSubject.getClass();

        Subject subject = (Subject) Proxy.newProxyInstance(cls.getClassLoader(), cls.getInterfaces(), dynamicProxy);
        subject.request();
    }
}

cglib dynamic proxy

Two kinds of dynamic agents are used in AOP source code to implement the function of intercepting entry: JDK dynamic agent and cglib dynamic agent.
The dynamic proxy mechanism of JDK can only proxy the class that implements the interface, otherwise it can not realize the dynamic proxy of JDK. Therefore, the dynamic proxy of JDK has some limitations. cglib implements the proxy for the class.
Its principle is to generate a subclass of the specified target class and override the method implementation enhancements. Because inheritance is used, the final modifier class cannot be proxied.

Because JAVA only allows single inheritance, and the proxy class generated by JDK itself inherits the Proxy class, cglib is used to implement inherited dynamic proxy.

CGLIB(Code Generation Library) is an open source project. It is a powerful, high-performance and high-quality code generation class library. It can extend Java classes and implement Java interfaces at runtime. Generally speaking, cglib can generate bytecodes dynamically at runtime.

The concrete realization is as follows:

/**
 * Specific subject objects, note that no interfaces are implemented
 *
 * @author Jonathan
 * @version 1.0.0
 * @date 2019/8/29 12:16
 * @since 1.0.0+
 */
public class RealSubject {

    public void request() {
        System.out.println("Access to Real Topics");
    }
}


import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
 * Dynamic proxy class
 *
 * @author Jonathan
 * @version 1.0.0
 * @date 2019/8/29 12:17
 * @since 1.0.0+
 */
public class CglibProxy implements MethodInterceptor {
    /**
     * Creating proxy objects through Enhancer
     */
    private Enhancer enhancer = new Enhancer();

    /**
     * Obtaining proxy objects through class objects
     * @param clazz class object
     * @return Proxy object
     */
    public Object getProxy(Class<?> clazz) {
        //Setting the parent class of the enhancer object
        enhancer.setSuperclass(clazz);
        //Setting up callbacks for enhancer
        enhancer.setCallback(this);
        return enhancer.create();
    }

    /**
     *
     * @param object Proxy object
     * @param method Method of Proxy Object
     * @param args Method parameters of the proxy object
     * @param methodProxy Agent Method
     * @return
     * @throws Throwable
     */
    @Override
    public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.println("before Dynamic Agent");
        //Call the proxy object of the newly generated cglib, the proxy method of the parent class to which it belongs
        Object result = methodProxy.invokeSuper(object, args);
        System.out.println("after Dynamic Agent");
        return result;
    }
}

/**
 * cglib The Call of Dynamic Agent
 *
 * @author Jonathan
 * @version 1.0.0
 * @date 2019/8/29 12:44
 * @since 1.0.0+
 */
public class CglibTest {

    public static void main(String[] args) {
        CglibProxy proxy = new CglibProxy();
        RealSubject realSubject = (RealSubject) proxy.getProxy(RealSubject.class);
        realSubject.request();
    }
}

Extension of Agent Model

As large as a system framework, enterprise platform, as small as code fragments and transaction processing, agent mode is used in many places. This mode should be the mode that we contact most. With AOP, we can write agents more simply. There are excellent tools like Spring AOP and AspectJ, which can be used.

In learning the AOP framework, we just need to figure out a few nouns: Aspect, pointCut, advice, target, proxy, join Point.

Tags: JDK Java jvm Programming

Posted on Thu, 29 Aug 2019 01:28:05 -0700 by davidppppppppppp