Hot deployment, unloading and
replacement of classes 1. The parent delegation mechanism of classLoader in Java (the default is system classLoader, also known as AppClassLoader, whose parents refer to Extend and BootTrap classLoader):
The loading of ClassLoader in Java adopts the parent delegation mechanism. When using the parent delegation mechanism to load a class, the following steps are used:
the current ClassLoader first checks whether the class has been loaded from the classes it has loaded, and if it has been loaded, it directly returns the originally loaded class.
Each class loader has its own loading cache. When a class is loaded, it will be put into the cache, and it can be returned directly when it is loaded next time.
When the loaded class is not found in the current classLoader's cache, the parent class loader is entrusted to load it. The parent class loader adopts the same strategy. First, it checks its own cache, and then entrusts the parent class of the parent class to load it until bootstrp ClassLoader.
When all parent class loaders are not loaded, it is loaded by the current class loader and put into its own cache, so that it can be returned directly next time there is a load request.
Another special case is contextClassLoader, which is mostly used in frameworks, which is equivalent to the backdoor of the first three.
2. Hot replacement of class (mainly by overriding the loadClass method in ClassLoader, adding the judgment of modification time, and calling the method of the new class through the reflection of the class to achieve hot replacement) The important method loadClass
in ClassLoader
ClassLoader.loadClass(...) is the entry point of the ClassLoader. When a class does not specify what loader to load, the JVM uses the AppClassLoader loader to load the unloaded class by default, and the entry of the called method is loadClass(...). If a class is loaded by a custom ClassLoader, the JVM will also call the custom ClassLoader.loadClass(...) method to load some other class files referenced inside the class. Overloading this method can realize the way of custom loading classes and abandon the parent delegation mechanism, but even if the parent delegation mechanism is not adopted, for example, the related classes in the java.lang package cannot be replaced by a custom class with the same name, mainly because the JVM When parsing and verifying the class, relevant judgments will be made.
The ClassLoader that comes with the defineClass
system, the default loader is AppClassLoader, ClassLoader loads a class, and finally calls the defineClass(...) method. At this time, I wonder if it is possible to repeatedly call the defineClass(...) method to load the same class Class (or modified), and finally found that if it is called multiple times, there will be related errors:
...
java.lang.LinkageError
attempted duplicate class definition
...
So if a class has been loaded by a ClassLoader instance, it cannot be loaded again by this ClassLoader instance (loading here refers to calling the defileClass(...) method to reload the bytecode, parsing, and verifying.) . The default AppClassLoader loader of the system will cache the loaded class internally. If it is reloaded, the cache will be taken directly. So for hot loading, you can only recreate a ClassLoader, and then load the class file that has been loaded.
1. The class object whose content needs to be modified during testing
package testjvm.testclassloader;
public class Hot {
public void hot() {
System.out.println(" version 1 : " + this.getClass().getClassLoader());
}
}
2. Override classLoad's UrlClassLoader class
package testjvm.testclassloader;
import java.io.File;
import java.io.FileNotFoundException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java .util.HashMap;
import java.util.Map;
/**
* The main function is to reload the changed .class file to achieve the effect of hot replacement 1
*/
public class HotSwapURLClassLoader extends URLClassLoader {
// cache the last modification time of the loaded class file
public static Map<String, Long> cacheLastModifyTimeMap = new HashMap<String, Long>();
// The path where the project class is located
public static String projectClassPath = "D:/workspace/JavaFunction/bin/";
// All test classes All under the same package
public static String packagePath = "testjvm/testclassloader/";
private static HotSwapURLClassLoader hcl = new HotSwapURLClassLoader();
public HotSwapURLClassLoader() {
// Set the path loaded by ClassLoader
super(getMyURLs());
}
public static HotSwapURLClassLoader getClassLoader() {
return hcl;
}
private static URL[] getMyURLs() {
URL url = null;
try {
url = new File(projectClassPath).toURI().toURL();
} catch (MalformedURLException e) {
e.printStackTrace();
}
return new URL[] { url };
}
/**
* Rewrite loadClass without using parent delegation mechanism (classes starting with "java." will still be loaded by the system default ClassLoader)
*/
@Override
public Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
Class clazz = null;
// Check whether the class has been loaded under the cache of
the HotSwapURLClassLoader instance // Different HotSwapURLClassLoader instances do not share the cache
clazz = findLoadedClass(name);
if (clazz != null) {
if (resolve) {
resolveClass(clazz);
}
// If the class has been modified, reload
if (isModify(name)) {
hcl = new HotSwapURLClassLoader();
clazz = customLoad(name, hcl);
}
return (clazz);
}
// If the class's package name Starting with "java.", there is the system default loader AppClassLoader to load
// java. Indicates that this is the original JDK class, such as java.lang.String
// The original loadClass package is: java.net;
if (name.startsWith("java.")) {
try {
// 得到系统默认的加载cl,即AppClassLoader
ClassLoader system = ClassLoader.getSystemClassLoader();
clazz = system.loadClass(name);
if (clazz != null) {
if (resolve)
resolveClass(clazz);
return (clazz);
}
} catch (ClassNotFoundException e) {
// Ignore
}
}
return customLoad(name, this);
}
public Class load(String name) throws Exception {
return loadClass(name);
}
/**
* 自定义加载
*
* @param name
* @param cl
* @return
* @throws ClassNotFoundException
*/
public Class customLoad(String name, ClassLoader cl) throws ClassNotFoundException {
return customLoad(name, false, cl);
}
/**
* 自定义加载
*
* @param name
* @param resolve
* @return
* @throws ClassNotFoundException
*/
public Class customLoad(String name, boolean resolve, ClassLoader cl) throws ClassNotFoundException {
// findClass() calls the findClass() method of ClassLoader overloaded in URLClassLoader
Class clazz = ((HotSwapURLClassLoader) cl).findClass(name);
if (resolve)
((HotSwapURLClassLoader) cl).resolveClass(clazz);
// The last modification time of the cache loaded class file
long lastModifyTime = getClassLastModifyTime(name);
cacheLastModifyTimeMap.put(name, lastModifyTime);
return clazz;
}
public Class<?> loadClass(String name) throws ClassNotFoundException {
return loadClass(name, false );
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
// TODO Auto-generated method stub
return super.findClass(name);
}
/**
* @param name
* @return the latest modification time of the .class file
*/
private long getClassLastModifyTime(String name) {
String path = getClassCompletePath(name );
File file = new File(path);
if (!file.exists()) {
throw new RuntimeException(new FileNotFoundException(name));
}
return file.lastModified();
}
/**
* Judge that this file keeps up Whether the ratio has been modified
*
* @param name
* @return
*/
private boolean isModify(String name) {
long lastmodify = getClassLastModifyTime(name);
long previousModifyTime = cacheLastModifyTimeMap.get(name);
if (lastmodify > previousModifyTime) {
return true;
}
return false;
}
/**
* @param name
* @return .class文件的完整路径 (e.g. E:/A.class)
*/
private String getClassCompletePath(String name) {
String simpleName = name.substring(name.lastIndexOf(".") + 1);
return projectClassPath + packagePath + simpleName + ".class";
}
}
3. 测试类:
package testjvm.testclassloader;
import java.lang.reflect.Method;
public class TestHotSwap {
public static void main(String[] args) throws Exception {
// Open the thread, if the class file is modified, hot replace
Thread t = new Thread (new MonitorHotSwap());
t.start();
}
}
class MonitorHotSwap implements Runnable {
// Hot is used for modification, to test hot loading
private String className = "testjvm.testclassloader.Hot";
private Class hotClazz = null ;
private HotSwapURLClassLoader hotSwapCL = null;
@Override
public void run() {
try {
while (true) {
initLoad();
Object hot = hotClazz.newInstance();
Method m = hotClazz.getMethod("hot");
// Print out relevant information
m.invoke(hot, null);
// Reload every 10 seconds
Thread.sleep(10000 );
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* load class
*/
void initLoad() throws Exception {
hotSwapCL = HotSwapURLClassLoader.getClassLoader();
// If the Hot class is modified, Then it will be reloaded and hotClass will also return the new
hotClazz = hotSwapCL.loadClass(className);
}
}
Modify "version 1" to "version 2" when the test is running, and you will see that the modified content of the dynamic output becomes "version 2".
3. Hot deployment of jar package
4. under Tomcat
Tool: Hot deployment of JavaRebel
class:
http://www.xuehuile.com/blog/abc337f9515449959ab6cebc19d70361.html
http://my.oschina.net/zhaoxj/blog/ 140266
http://www.jiancool.com/article/84343280279/
http://wenku.baidu.com/view/1c5559f4ba0d4a7302763ab8.html
http://www.blogjava.net/heavensay/archive/2015/11/06/ 389685.html hot deployment and uninstallation of classes
http://blog.csdn.net/mycomputerxiaomei/article/details/24470465 Dynamic loading of jar files
http://www.cnblogs.com/xwdreamer/archive/2011/12/05/ 2296918.html
http://huangqiqing123.iteye.com/blog/1461624
classLoader:
http://my.oschina.net/aminqiao/blog/262601
http://www.cnblogs.com/zhanjindong/p/3952445.html
http://calmness.iteye.com/blog/83978
Java project hot deployment
Guess you like
Origin http://43.154.161.224:23101/article/api/json?id=326248148&siteId=291194637
Recommended
Ranking