“This is the 7th day of my participation in the Gwen Challenge in November. Check out the details: The Last Gwen Challenge in 2021.”

1. 【Proxy Pattern】

Why “agency”? There are many examples in life, such as entrusted business and so on. Agent means that the agent is unable or unwilling to complete something and needs to find someone to complete it on his behalf, which is the reason for the existence of “agent”. For example, I need to go abroad, but I don’t want to apply for a visa, book air tickets and hotels by myself.

2. Overview of dynamic proxies

Dynamic proxy simply means intercepting direct access to real object methods and enhancing the functionality of real object methods

Dynamic proxies are: Proxy objects created by proxy classes at runtime are called dynamic proxies, that is, in this case, proxy classes are not defined in Java code, but are dynamically generated at runtime according to our “instructions” in Java code. The dynamic proxy will dynamically generate a proxy for the object you want to obtain. A dynamic proxy can enhance the methods of a propped object and do whatever you want before and after the method execution without modifying the method source code. Dynamic proxy technology is used in the framework of the majority, such as: Struts1, Struts2, Spring and Hibernate, some of the mainstream framework technology of late learning have used dynamic proxy technology.

3. Case introduction

Now, suppose we want to implement this requirement: In the enterprise, the large system of execution of each business layer method requires corresponding logging, such as when the method completes, the information such as how long time, according to the log information, we can see the situation of the system implementation, especially when there is an error in the system, the log information is particularly important. Now there is an implementation idea like this, the business layer implementation class code is as follows:

public interface SchoolService{
     String login(String loginName, String passWord);
     String getAllClazzs(a); }public class SchoolServiceImpl implements SchoolService {

    @Override
    public String login(String loginName, String passWord) {
        
        // Start time of method execution
        long startTimer = System.currentTimeMillis();
        
        try {
            Thread.sleep(500);
            if("admin".equals(loginName) && "123456".equals(passWord)){
                return "success"; }}catch (Exception e) {
            throw new RuntimeException("Login exception");
        }
        long endTimer = System.currentTimeMillis();
        When and how long did it take to complete
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println("Login method execution ->"+sdf.format(endTimer)+", time:"+(endTimer - startTimer));
        
        return "Incorrect login name or password";
    }
​
    @Override
    public String getAllClazzs(a) {
        / / time
        long startTimer = System.currentTimeMillis();
        try {
            Thread.sleep(1000);
            return "Returned all classes (Class 1, Class 2, Class 3)";
        } catch (Exception e) {
            throw new RuntimeException("Class exception query");
        }finally{
            long endTimer = System.currentTimeMillis();
            When and how long did it take to complete
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            System.out.println("GetAllClazzs method execution ->"+sdf.format(endTimer)+", time:"+(endTimer - startTimer)); }}}Copy the code

We record the start time and end time when the method of the business layer is executed each time. In this way, although the deadline and time consumption of each method can be recorded, the code is bloated, and the code itself is irrelevant to the business function. So is there a way to solve this problem?

Dynamic proxy is a very good means to solve this kind of problem, through dynamic proxy we can provide a dynamic proxy object for the business layer implementation class object. The proxy object can be used to proxy all methods of the implementation class, and enhance the function of the proxy method. That is to say as long as the call of the proxy implementation class method, the method of execution will enter into a proxy object, proxy objects can record the start time, before the carrying out of the way then go to trigger the execution of the method, the method completes by proxy objects to records over time then later calculation time as logging, Because the logging of methods is done by the agent, the methods of the proxied object do not need to log their own separate operations. This results in a very good design model.

Now let’s use dynamic proxy to write a logging proxy class:

The code is as follows:

public class LogProxy {
    // Provides a method for producing proxy objects that need to be proxied.
    public static Object getProxy(Object obj) {
        return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj
                .getClass().getInterfaces(), new InvocationHandler() {
​
            @Override
            public Object invoke(Object proxy, Method method, Object[] args)
                    throws Throwable {
                // Record the start time
                long startTimer = System.currentTimeMillis();
                try {
                       // To actually trigger the execution of the method in the proxied object
                    return method.invoke(obj, args);
                } catch (Exception e) {
                    throw new RuntimeException(e);
                } finally {
                    long endTimer = System.currentTimeMillis();
                    When and how long did it take to complete
                    SimpleDateFormat sdf = new SimpleDateFormat(
                            "yyyy-MM-dd HH:mm:ss");
                    System.out.println(method.getName() + "Method execution ->"
                            + sdf.format(endTimer) + ", time:"+ (endTimer - startTimer)); }}}); }}Copy the code

5. Focus on classes and methods

In the code above, the getProxy method is a proxy object used to get an implementation class object. In this code, if you want to understand the Java dynamic proxy mechanism, you first need to understand the following related classes or interfaces:

Java.lang.reflect.proxy: This is the main class of Java’s dynamic Proxy mechanism, which provides a static method to dynamically generate Proxy classes and their objects for a set of interface implementation classes.

newProxyInstance()Argument parsing

This method is used to generate dynamic proxy class instances for the specified class loader, a set of interfaces, and the calling handler

public static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)

  1. obj.getClass().getClassLoader()After the target object gets all the information about the class through the getClass method, it calls the getClassLoader() method to get the classloader. After obtaining a class loader, this type of loader can be used to load the generated proxy classes into the JVM, or Java Virtual machine, while the program is running for runtime use!
  2. obj.getClass().getInterfaces()Gets all interface information for the proxied class so that the generated proxy class can have all methods in the proxy class interface.
  3. InvocationHandlerThis is the invocation handler interface, which defines a custom invoke method to focus on method calls on dynamic proxy class objects, where the delegate class methods are typically handled and accessed.

Parameters to the invoke method

public Object invoke(Object proxy, Method method, Object[] args)

  1. Object Proxy is a proxy Object generated by the Object Proxy. This Object is not specifically understood here, but I think it is a proxy Object generated in memory.
  2. Method Method: An abstraction of the proxied Method on the proxied object.
  3. Object[] args: arguments in the proxied method. Because the number of arguments is variable, it’s represented by an array of objects.

After the proxy class definition is complete, the business layer implementation class method does not need to declare the logging code itself, because the proxy object will help with the logging. The modified implementation class code is as follows:

public class SchoolServiceImpl implements SchoolService {
​
    @Override
    public String login(String loginName, String passWord) {
        try {
            Thread.sleep(500);
            if("admin".equals(loginName) && "123456".equals(passWord)){
                return "success"; }}catch (Exception e) {
            throw new RuntimeException("Login exception");
        }
        return "Incorrect login name or password";
    }
​
    @Override
    public String getAllClazzs(a) {
        try {
            Thread.sleep(1000);
            return "Returned all classes (Class 1, Class 2, Class 3)";
        } catch (Exception e) {
            throw new RuntimeException("Class exception query"); }}}Copy the code

Start using dynamic proxies to access methods:

public class TestMain {
    public static void main(String[] args) {
        // Get the proxy object of the business layer implementation object, and the business layer implementation object will be proxied
        SchoolService schoolService = (SchoolService) LogProxy.getProxy(new SchoolServiceImpl());
        
        System.out.println(schoolService.login("admin"."1234256")); System.out.println(schoolService.getAllClazzs()); }}Copy the code

Method. Invoke (obj, args) is used to invoke the method. Invoke (obj, args) is used to invoke the method. The proxy object then records the method end time and outputs the log. The whole process is then perfectly implemented by proxy.

6. Summary

Dynamic proxies are very flexible and can be used for any interface implementation class object

Dynamic proxy can be proxy for all methods of all interfaces of the object being proxy, dynamic proxy can be implemented without changing the method source code to enhance the function of the method,

The bytecode of a dynamic proxy class is dynamically generated by Java reflection while the program is running, without the programmer having to manually write its source code.

Dynamic proxy classes not only simplify programming but also improve the extensibility of software systems because Java reflection can generate any type of dynamic proxy class.

Dynamic proxies also improve development efficiency.

Disadvantages: Can only be used as a proxy object for the implementation class of the interface, ordinary class is not used as a proxy object.