Hot replacement of Java classes — reprint
•
Java
Build an online upgrade system based on Java
In this article, we will not explain the details of Java classloader in too much detail, but focus on the basic concepts related to building an online upgrade system. For detailed information about classloader, you can refer to many materials, and interested readers can study it by themselves. To build an online upgrade system, An important technology is to be able to implement hot replacement of Java classes -- that is, class replacement without stopping the running system (object) upgrade and replacement. Java classloader is the basis for realizing this technology. In Java, the class instantiation process is divided into two parts: class loading and class instantiation. Class loading is divided into explicit loading and implicit loading. When you use the new keyword to create a class instance, you implicitly include the class loading process. For the explicit addition of a class In terms of load, the more commonly used is class forName。 In fact, they all complete the actual loading of the class by calling the loadclass method of the classloader class. Directly calling the loadclass method of classloader is another uncommon technique for explicitly loading classes.
Classloader has certain hierarchical relationships and rules when loading classes. In Java, there are four types of class loaders: bootstrapclassloader, extclassloader, appclassloader and user-defined classloader. These four kinds of loaders are responsible for loading classes in different paths, and form a hierarchy of class loading. Bootstrapclassloader is at the top level of the classloader hierarchy and is responsible for sun boot. class. The loading of classes under the path. The default is the core API in the JRE / lib directory or the jar package specified by the - xbootclasspath option. The loading path of extclassloader is Java Ext.dirs, the default is JRE / lib / ext directory or - DJava Ext.dirs loads the jar package in the specified directory. The loading path of appclassloader is Java class. Path, which defaults to the value set in the environment variable classpath. It can also be specified through - classpath selection. User defined classloader can customize its own class loading process according to the needs of users, and dynamically load the specified class in real time at run time. The hierarchical relationship of these four kinds of loaders is shown in. Generally speaking, these four kinds of loaders form a parent-child relationship, and the upper level is the lower level parent loader. When loading a class, you will first check whether the specified class has been loaded one by one from the bottom up. If it has been loaded, you will directly return the reference of the class. If the specified class has not been loaded at the top level, it will try to load one by one from top to bottom until the user-defined class loader. If it fails, an exception will be thrown. The loading process of Java classes is shown in.
Each class loader has its own namespace. For the same class loader instance, only one class with the same name can exist and be loaded only once. No matter whether the class is changed or not, the next time it needs to be loaded, it just returns the loaded class reference directly from its own cache. The application classes we write are loaded by appclassloader by default. When we use the new keyword or class When the class is loaded by forname, the class to be loaded is called by new or class Class loader for class forname (also appclassloader). In order to realize the hot replacement of Java classes, we must first realize the coexistence of different versions of instances of classes with the same name in the system. Through the above introduction, we know that in order to realize the coexistence of different versions of the same class, we must load different versions of the class through different class loaders. In addition, in order to bypass Java For the given loading process of classes, we need to implement our own class loader and fully control and manage the loading process of classes. In order to fully control the class loading process, our custom class loader needs to inherit directly from classloader. First, let's introduce some important methods related to hot replacement in classloader class. Findloadedclass: each class loader maintains its own loaded class namespace, in which two classes with the same name cannot appear. All classes loaded through the class loader, whether directly or indirectly, are saved in their own namespace. This method is to find out whether the specified class already exists in the namespace. If it exists, it will return to the reference of the class, otherwise it will return null. Here, it directly means that the class loader exists on the loading path of the class loader and the loader completes the loading, and indirectly means that the class loader entrusts the loading of the class to other class loaders to complete the actual loading of the class. Getsystemclassloader: a new method in Java 2. This method returns the classloader used by the system. You can transfer part of the work to the system class loader through this method in your own customized class loader. Defineclass: this method is a very important method in classloader. It receives the class bytecode represented by byte array and converts it into a class instance. When this method converts a class, it will first require to load the parent class and the implemented interface class of the class. Loadclass: the entry method of the loading class, which is called to complete the explicit loading of the class. Through the re implementation of this method, we can completely control and manage the loading process of classes. Resolveclass: links a specified class. This is a necessary method to ensure the availability of classes in some cases. See the description of this method in the "execution" chapter of the Java language specification for details. After understanding the above methods, let's implement a custom class loader to complete the loading process: we specify some class collections that must be loaded directly by the class loader for the class loader. When the class loader loads classes, if the class to be loaded belongs to the collection that must be loaded by the class loader, Then it directly completes the class loading, otherwise it delegates the class loading to the class loader of the system. Before giving the sample code, there are two points to explain: 1. In order to realize the coexistence of different versions of the same class, these different versions must be loaded by different class loaders. Therefore, the loading of these classes cannot be entrusted to the system loader because they have only one copy. 2. In order to achieve this, the system default classloader delegation rule cannot be adopted, that is, the parent loader of our customized classloader must be set to null. The implementation code of the customized class loader is as follows: private string basedir// The base directory of class files that need to be loaded directly by the class loader private HashSet dynaclazns// The class name that needs to be directly loaded by the class loader is public customcl (string basedir, string [] clazns) {super (null); / / specify that the parent class loader is null this.basedir = basedir; dynaclazns = new hashset(); loadclassbyme (clazns);} private void loadClassByMe(String[] clazns) { for (int i = 0; i < clazns.length; i++) { loadDirectly(clazns[i]); dynaclazns.add(clazns[i]); } } private Class loadDirectly(String name) { Class cls = null; StringBuffer sb = new StringBuffer(basedir); String classname = name.replace('.',File.separatorChar) + ".class"; sb.append(File.separator + classname); File classF = new File(sb.toString()); cls = instantiateClass(name,new FileInputStream(classF),classF.length()); return cls; } private Class instantiateClass(String name,InputStream fin,long len){ byte[] raw = new byte[(int) len]; fin.read; fin.close(); return defineClass(name,raw,raw.length); } protected Class loadClass(String name,boolean resolve) throws ClassNotFoundException { Class cls = null; cls = findLoadedClass(name); if(!this.dynaclazns.contains(name) && cls == null) cls = getSystemClassLoader().loadClass(name); if (cls == null) throw new ClassNotFoundException(name); if (resolve) resolveClass(cls); return cls; } } In the implementation of this class loader, all classes specified to be loaded directly by it are loaded when the loader is instantiated. When loading a class through loadclass, if the class has not been loaded and does not belong to the list that must be loaded by this class loader, it is entrusted to the system loader for loading. Understanding this implementation is only one step away from realizing the hot replacement of classes. We will explain this in detail in the next section. In this section, we will combine the characteristics of the class loader described earlier and realize the hot replacement of Java classes based on the custom class loader implemented in the previous section. First, we change the class name of the class loader implemented in the previous section from customcl to hotswapcl to clearly express our intention. Now let's introduce our experimental method. For simplicity, our package is the default package, there is no hierarchy, and all error handling is omitted. The class to be replaced is foo. The implementation is very simple. It only contains one method, sayhello: create a new directory Swap under the current working directory and put the compiled foo The class file is placed in this directory. Next, we will use the hotswapcl we wrote earlier to implement the hot substitution of this class. The specific approach is: we write a timer task and execute it every 2 seconds. Among them, we will create a new class loader instance, load the foo class, generate the instance, and call the sayhello method. Next, we will modify the print content of the sayhello method in the foo class, recompile it, and replace the original foo when the system is running Class, we will see that the system will print out the changed content. The implementation of the scheduled task is as follows (other codes are omitted, please supplement them by yourself): method m = foo. Getclass()< a href="%20https://www.jb51.cc/tag/getmethod/%20" target="_ blank" class="keywords">getmethod("sayHello",new Class[]{});
The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
二维码