Java project hot deployment

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

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326248148&siteId=291194637