The proxy mode uses proxy objects to complete user requests and shield users from accessing real objects.
The proxy mode has many uses. For example, for security reasons, it is necessary to shield the client from directly accessing the real object; or in remote calls, it is necessary to use proxy objects to handle technical details in remote methods; or in order to improve the system, Real objects are encapsulated to achieve the purpose of lazy loading.
When the system starts, separating the methods that consume the most resources using proxy mode can speed up the system startup and reduce the user's waiting time. When the user is actually making a query, the proxy class loads the real class to complete the user's request. This is the purpose of using proxy mode to achieve lazy loading.
1. Static proxy implementation:
Theme interface:
public interface IDBQuery { String request(); }
Real theme:
public class DBQuery implements IDBQuery { public DBQuery(){ try { Thread.sleep(10000); } catch (Exception e) { e.printStackTrace(); } } public String request() { return "string request"; } }
Proxy 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 a real class that implements a common interface, and the proxy The class refers to the real class object, and the time-consuming operations are implemented in the proxy class method.
Dynamic proxy:
Dynamic proxy is a dynamically generated proxy class at runtime. That is: the bytecode of the proxy class is generated and loaded into the current classloader at runtime. Compared with static proxies, dynamic proxies do not need to encapsulate a completely identical encapsulation class for real attention. If there are many subject interfaces, it is very annoying to write a proxy method for each interface. If the interface changes, the real class Both the agent class and the agent class need to be changed, which is not conducive to system maintenance; secondly, using some dynamic agent generation methods can even specify the execution logic of the agent class at runtime, thereby greatly improving 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()); } }
In addition, you can also use CGLIB and javassist dynamic proxies similar to jdk dynamic proxies, but the creation process of jdk dynamic classes is the fastest, because the differentiateclass() method of this built-in implementation is defined as a native implementation, so the performance is better than other. In terms of function calls of proxy classes, JDK's dynamic proxy is not as good as CGLIB and javassist dynamic proxy, and javassist dynamic proxy has the worst performance quality, even inferior to JDK's implementation. In actual development applications, the method calling frequency of the proxy class is much higher than the actual generation frequency of the proxy class, so the method calling performance of the dynamic proxy should become a performance concern. JDK dynamic proxies force the proxy class and real theme to implement a unified interface. CGLIB and javassist dynamic proxies do not have such a requirement.
In Java, the implementation of dynamic proxy involves the use of classloader. Taking CGLIB as an example, we briefly describe the loading process of dynamic classes. To use CGLIB to generate a dynamic proxy, you first need to generate an instance of the Enhancer class and formulate a callback class for handling proxy services. In the enhancer.create() method, the DefaultGeneratorStrategy.Generate() method is used to generate the bytecode of the proxy class and save it in a byte array. Then call the reflectUtils.defineClass() method, and through reflection, call the ClassLoader.defineClass() method to load the bytecode into the classloader to complete the loading of the class. Finally, through the reflectUtils.newInstance() method, the dynamic class instance is generated through reflection and the instance is returned. Other details of the process are different, but the generation logic is the same.
The above is the entire content of this article, I hope it will be helpful to everyone's study.
For more articles related to the proxy mode of java design optimization, please pay attention to the PHP Chinese website!