A comprehensive explanation of Java static proxy and dynamic proxy

1. The role of the proxy model

The proxy mode in Java is a common design pattern. The proxy mode can enhance the function of the class without changing the original code. The proxy mode includes static proxy and dynamic proxy. The underlying mechanism of AOP is dynamic proxy.

The proxy pattern is a relatively well-understood design pattern. Simply put,  we use proxy objects to replace access to real objects, so that we can provide additional functional operations and expand the functions of the target object without modifying the original target object.

The following will give a comprehensive explanation of the two proxy modes.

2. Static proxy

Static proxy is the code that has determined the proxy class during compilation, and both the proxy class and the proxy class implement the same interface or inherit from the same parent class. The advantage of static proxy is that it is simple to write, easy to understand and maintain. However, if multiple classes need to be proxied, the number of proxy classes will increase, and the code of the proxy class needs to be manually maintained when the methods of the proxy class and the proxy class increase.

Here is a simple static proxy example:

public interface Subject {
    void request();
}

public class RealSubject implements Subject {
    @Override
    public void request() {
        System.out.println("RealSubject:request()");
    }
}

public class ProxySubject implements Subject {
    private RealSubject realSubject;

    public ProxySubject(RealSubject realSubject) {
        this.realSubject = realSubject;
    }

    @Override
    public void request() {
        System.out.println("ProxySubject:before request()");
        realSubject.request();
        System.out.println("ProxySubject:after request()");
    }
}

public class Client {
    public static void main(String[] args) {
        RealSubject realSubject = new RealSubject();
        ProxySubject proxySubject = new ProxySubject(realSubject);
        proxySubject.request();
    }
}

 In the above example, RealSubjectthe proxy class is ProxySubjectthe proxy class, and the proxy class implements Subjectthe interface and holds an instance of the proxy class RealSubject. In the method of the proxy class request(), the method of the proxy class is called request(), and its own processing logic is added before and after.

3. Dynamic agent

The dynamic proxy is to dynamically generate the code of the proxy class at runtime, and does not need to know the code of the proxy class in advance. There are two main forms of dynamic proxy in Java, one is interface-based dynamic proxy, and the other is class-based dynamic proxy.

In order to realize dynamic proxy, what problems need to be solved?

Question 1: How to dynamically create a proxy class and its objects based on the proxy class loaded into memory

Question 2: When calling a method through the object of the proxy class, how to dynamically call the method of the same name in the proxy class

Interface-based dynamic proxy

Interface-based dynamic proxy means that the proxy class and the proxy class implement the same interface, and the proxy class is dynamically generated at runtime, without manually writing the code of the proxy class.

In the Java dynamic proxy mechanism, InvocationHandlerinterfaces and Proxyclasses are the core.

ProxyThe most frequently used method in the class is: newProxyInstance(), which is mainly used to generate a proxy object.

public static Object newProxyInstance(ClassLoader loader,
                                       Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
{
      ......
}

This method has a total of 3 parameters:

  1. loader  : class loader, used to load proxy objects.
  2. interfaces  : some interfaces implemented by the proxy class;
  3. h  : the object that implements  InvocationHandler the interface;

 To implement a dynamic proxy, you must also implement InvocationHandlerto customize the processing logic. When our dynamic proxy object calls a method, the call of this method will be forwarded to the method that implements the InvocationHandlerinterface class invoketo call.

public interface InvocationHandler {

    /**
     * 当你使用代理对象调用方法的时候实际会调用到这个方法
     */
    public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;
}

invoke()The method has the following three parameters:

  1. proxy : dynamically generated proxy class
  2. method : corresponds to the method called by the proxy class object
  3. args : the parameters of the current method method

That is to say: when the proxy object you created through Proxythe class calls the method, it will actually call the method of the class that implements the interface . newProxyInstance()InvocationHandlerinvoke()You can invoke()customize the processing logic in the method, such as what to do before and after the method is executed.

Here is an example of an interface-based dynamic proxy:

public interface Subject {
    void request();
}
// 被代理类
public class RealSubject implements Subject {
    @Override
    public void request() {
        System.out.println("RealSubject:request()");
    }
}
// 解决问题二
public class DynamicProxySubject implements InvocationHandler {
    private Object realSubject;

    public DynamicProxySubject(Object realSubject) {
        this.realSubject = realSubject;
    }
    //当我们通过代理类的对象,调用方法request时,就会自动的调用如下的方法: invoke()
    //将被代理类要执行的方法的功能就言明在invoke()中
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //method: 即为代理类对象调用的方法,此方法也就作为了被代理类对象要调用的方法
        //realSubject: 被代理类的对象
        System.out.println("DynamicProxySubject:before " + method.getName() + "()");
        Object result = method.invoke(realSubject, args);
        System.out.println("DynamicProxySubject:after " + method.getName() + "()");
        //上述方法的返回值就作为当前类中的invoke()的返回值。
        return result;
    }
}

public class Client {
    public static void main(String[] args) {
        RealSubject realSubject = new RealSubject();
        DynamicProxySubject dynamicProxySubject = new DynamicProxySubject(realSubject);
        //调用此方法,返回一个代理类的对象。解决问题一
        Subject proxySubject = (Subject)Proxy.newProxyInstance(realSubject.getClass().getClassLoader(),         
        realSubject.getClass().getInterfaces(), dynamicProxySubject);
        proxySubject.request();
    }
}

In the above example, `RealSubject` is the proxy class, `DynamicProxySubject` is the proxy class, the proxy class implements the `InvocationHandler` interface, and calls the corresponding method of the proxy class in the `invoke()` method of the proxy class, And add your own processing logic before and after. In the client code, an instance of the proxy class is dynamically generated by calling the `Proxy.newProxyInstance()` method.

Class-based dynamic proxy

Class-based dynamic proxy means that both the proxy class and the proxy class are classes, and the proxy class is dynamically generated at runtime, without manually writing the code of the proxy class. The class-based dynamic proxy in Java is mainly realized through the bytecode generation framework, and the more commonly used bytecode generation frameworks include CGLIB and ASM. Here is an example of a class-based dynamic proxy (implemented using CGLIB):

public class RealSubject {
    public void request() {
        System.out.println("RealSubject:request()");
    }
}

public class DynamicProxySubject implements MethodInterceptor {
    private Object realSubject;

    public DynamicProxySubject(Object realSubject) {
        this.realSubject = realSubject;
    }

    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("DynamicProxySubject:before " + method.getName() + "()");
        Object result = proxy.invoke(realSubject, args);
        System.out.println("DynamicProxySubject:after " + method.getName() + "()");
        return result;
    }
}

public class Client {
    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(RealSubject.class);
        enhancer.setCallback(new DynamicProxySubject(new RealSubject()));
        RealSubject proxySubject = (RealSubject) enhancer.create();
        proxySubject.request();
    }
}

In the above example, RealSubjectit is the proxy class and DynamicProxySubjectthe proxy class. The proxy class implements the interface, and calls the corresponding method of the proxy class in the method of the MethodInterceptorproxy class , and adds its own processing logic before and after. intercept()In the client code, Enhanceran instance of the proxy class is generated by calling the class provided by CGLIB.

Four. Summary

Static proxy and dynamic proxy are both specific implementations of the proxy pattern, both of which can enhance the functionality of a class, but in different ways. The code of the proxy class has been determined during the compilation of the static proxy, which is suitable for proxying a small number of classes; the code of the proxy class is dynamically generated by the dynamic proxy at runtime, which is suitable for proxying a large number of objects or uncertain which class to proxy.

The static agent in Java needs to manually write the code of the agent class, which is not flexible enough, but the efficiency is high; the dynamic agent does not need to manually write the code of the agent class, which is more flexible, but the efficiency is low.

Both static proxies and dynamic proxies in Java are interface-based proxies, so the proxied class must implement the interface.

Dynamic proxies are implemented in Java through the reflection mechanism, which will bring certain performance overhead. In addition, because the dynamic proxy is a proxy class dynamically generated at runtime, it is not easy to debug.

In practical applications, static proxy or dynamic proxy can be selected according to the specific situation, such as the number of classes that need to be proxied, the structure of the proxy class, the complexity of the proxy class, the life cycle of the proxy class and other factors can affect the choice.

Guess you like

Origin blog.csdn.net/weixin_44863237/article/details/130426299