java designs an optimized proxy pattern

  • 2020-05-05 11:20:39
  • OfStack

The proxy pattern USES the proxy object to complete the user's request, masking the user's access to the real object.

The proxy pattern has many USES, such as shielding clients from direct access to real objects for security reasons. Or in a remote invocation, you need to use a proxy object to handle the technical details of a remote method. Or to improve the system, real objects are encapsulated to achieve lazy loading.

When the system is started, the most resource-consuming methods are separated using the proxy pattern to speed up system startup and reduce user wait time. After the user is actually doing the query, the proxy class loads the real class and completes the user request. This is what lazy loading is all about using the proxy pattern.

1. Static proxy implementation:

Theme interface:


public interface IDBQuery {
   String request();
 }

Real topic:


public class DBQuery implements IDBQuery {
  public DBQuery(){
    try {
      Thread.sleep(10000);
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
  public String request() {
    return "string request";
  }
}

Agent class:


public class IDBQueryProxy implements IDBQuery {
  private DBQuery dbquery; 
  public String request() {
    if(dbquery==null)
      dbquery = new DBQuery();
    return dbquery.request();
  }
}

Finally, the main function:


public class ProxyText {
  public static void main(String[] args) {
    IDBQuery dbquery = new IDBQueryProxy();
    System.out.println(dbquery.request()); 
  }
}

Static proxy note that the proxy class is the interface that real classes implement, and the proxy class references real class objects, implementing time-consuming operations in proxy class methods.

dynamic agent:

Dynamic proxy is the dynamic generation of proxy classes at runtime. That is, the bytecode of the proxy class is generated at runtime and loaded with the current classloader. Compared with static proxy, dynamic proxy does not need to encapsulate a form of exactly the same encapsulation class for real attention, if there are many theme interfaces, it is very annoying to write a proxy method for each interface, if the interface has changes, real class and proxy class need to change, which is not conducive to system maintenance; Second, some of the dynamic proxy generation methods can even be used to specify the execution logic of the proxy class when running, thus greatly increasing the flexibility of the system.

Theme interface:


public interface IDBQuery {
   String request();
 }

jdk proxy class:


public class JdbDbqueryHandler implements InvocationHandler{
  IDBQuery idbquery = null;
  @Override
  public Object invoke(Object proxy, Method method, Object[] args)
      throws Throwable {
    if(idbquery==null){
      idbquery = new DBQuery();
    }
    return idbquery.request();
  }
  public static IDBQuery createJdbProxy(){
    IDBQuery jdkProxy = (IDBQuery) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(),
        new Class[]{IDBQuery.class}, new JdbDbqueryHandler());
    System.out.println("JdbDbqueryHandler.createJdbProxy()");
    return jdkProxy;
  }

}

Main function:


public class ProxyText {
  public static void main(String[] args) {
    IDBQuery idbQuery = JdbDbqueryHandler.createJdbProxy();
    System.out.println(idbQuery.request());
  }
}

Alternatively, you can use CGLIB and javassist dynamic proxies that are similar to jdk dynamic proxies, but jdk dynamic classes are created the fastest because the built-in difineclass() method is defined as the native implementation and therefore performs better than the others. On the function calls of the proxy class, JDK's dynamic proxy is not as good as CGLIB and javassist's dynamic proxy, while javassist's dynamic proxy has the worst performance quality and is even worse than JDK's implementation. In the actual development application, the method invocation frequency of proxy class is much higher than the actual generation frequency of proxy class, so the performance of dynamic proxy method invocation should become the performance concern. JDK dynamic proxies mandate a uniform interface between proxy classes and real topics, while CGLIB and javassist dynamic proxies do not.

In java, the implementation of dynamic proxy involves the use of classloader. Taking CGLIB as an example, the loading process of dynamic classes is briefly described. To generate a dynamic proxy using CGLIB, you first need to generate an instance of the Enhancer class and formulate a callback class to handle the proxy business. In the enhancer.create () method, the DefaultGeneratorStrategy.Generate () method is used to generate the bytecode for the proxy class and store it in the byte array. Then the reflectUtils.defineClass () method is called, and the ClassLoader.defineClass () method is called by reflection to load the bytecode into classloader and complete the loading of the class. Finally, through the reflectUtils.newInstance () method, a dynamic class instance is generated by reflection and returned. Others differ from the process details, but the generation logic is the same.

The above is the entire content of this article, I hope to help you with your study.


Related articles: