SoFunction
Updated on 2025-05-13

Detailed explanation of how to implement hot loading and hot deployment of classes in Java

Preface

In Java, implementing Hot Load and Hot Deploy classes allows us to dynamically replace or update classes and resources without restarting the application. This is very useful for our development and debugging and can improve development efficiency.

Basic concepts:

  • Hot Load:Refers to reload the bytecode of the class at runtime and replace the old version of the class definition. Usually used in development environments, you can quickly see the effect of code modifications.
  • Hot Deploy:It refers to redeploying the entire application or part of the module (for example, WAR package, JAR package) at runtime, usually including updates to multiple classes.

Implementation method:

Custom class loader (ClassLoader):

  • principle:

    • Java's class loaders have a delegate mechanism (parent delegation model), but the same class loaded by different class loaders will be considered different classes.
    • You can create a custom class loader to load new versions of classes.
    • Replace old versions of classes with reflection or other mechanisms.
  • step:

    Create a customClassLoader, rewritefindClassMethod, implement the loading of bytecode of the class from a specific location (for example, file system, network).

    Create a new custom when a class is needed.ClassLoaderExample.

    Use the newClassLoaderThe instance loads the new version of the class.

    Use reflection or other mechanisms to replace the new version of the class with the old version.

    Uninstall the old class loader (need to make sure that no objects refer to the classes loaded by the old class loader, otherwise it cannot be uninstalled).

  • advantage:

    • High flexibility and can fully control the loading process of the class.
    • A more fine-grained hot loading can be achieved (for example, only partial classes are updated).
  • shortcoming:

    • The implementation is complex and requires handling of the class loader's delegate relationship, class unloading and other issues.
    • This may result in class version conflicts or memory leaks (if the older version of the class is not uninstalled correctly).
  • Sample code (simplified version):

    import .*;
    import ;
    
    public class MyClassLoader extends ClassLoader {
    
        private String classPath;
    
        public MyClassLoader(String classPath) {
             = classPath;
        }
    
        @Override
        protected Class<?> findClass(String name) throws ClassNotFoundException {
            try {
                byte[] classData = loadClassData(name);
                if (classData == null) {
                    throw new ClassNotFoundException();
                } else {
                    return defineClass(name, classData, 0, );
                }
            } catch (IOException e) {
                throw new ClassNotFoundException("Failed to load class " + name, e);
            }
        }
    
        private byte[] loadClassData(String className) throws IOException {
            String fileName = classNameToPath(className);
              File file = new File(fileName);
              if(!()){
                    return null; // or throw exception
              }
    
            try (InputStream ins = new FileInputStream(file);
                 ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
    
                byte[] buffer = new byte[1024];
                int bytesRead;
                while ((bytesRead = (buffer)) != -1) {
                    (buffer, 0, bytesRead);
                }
                return ();
    
            }
        }
    
    
        private String classNameToPath(String className) {
            return classPath +  + ('.', ) + ".class";
        }
    
        public static void main(String[] args) throws Exception {
          String classPath = "path/to/your/classes"; // Replace with the root directory where your class file is located
           // First loading      MyClassLoader classLoader1 = new MyClassLoader(classPath);
          Class<?> class1 = (""); // Replace with the fully qualified name of the class you want to load      Object instance1 = ();
          Method method1 = ("myMethod");
          (instance1);
    
          // Mock it and recompile it      ("--- Modify and recompile ----");
          (5000); // Wait for the compilation to complete
          // Second load (using new class loader)      MyClassLoader classLoader2 = new MyClassLoader(classPath);
          Class<?> class2 = ("");
          Object instance2 = ();
          Method method2 = ("myMethod");
          (instance2); // Call the new version of the method  }
    
    }
    

    :

    package ;
     public class MyClass{
        public void myMethod(){
           ("MyClass version 1");
        }
     }
    

Java Instrumentation API:

  • principle:
    • The Java Instrumentation API allows you to modify the bytecode of a class at runtime.
    • Can be usedorMethods redefine or convert classes.
  • step:

    Create a Java Agent (a JAR file containingpremainoragentmainmethod).

    existpremainoragentmainIn the method, obtainInstrumentationExample.

    useMethod Register oneClassFileTransformer

    existIn the method, modify the bytecode of the class.

    use-javaagentCommand line parameters start the application and specify the JAR file of the Agent.

    At runtime, when the class is loaded,The method will be called, and you can modify the bytecode of the class here.

  • advantage:
    • Powerful, can modify the bytecode of any class.
    • No custom class loader is required.
  • shortcoming:
    • The implementation is complex and requires understanding of Java bytecode.
    • May affect the performance of the application.
    • Not all JVMs support the Instrumentation API.
  • Example:
  • refer toJava Instrumentation APIDocumentation and examples.

Usage Tools (recommended):

  • JRebel (Commercial):Powerful hot deployment tool, supporting a variety of frameworks and application servers.
  • Spring Boot DevTools:The development tools provided by Spring Boot support automatic restart and hot deployment.
  • HotSwapAgent:An open source hot deployment tool that supports multiple frameworks and application servers.
  • DCEVM (Dynamic Code Evolution VM):An enhanced version of HotSpot VM supports more powerful hot deployment features.
  • IDE support:Many IDEs (such as IntelliJ IDEA, Eclipse) have built-in hot deployment functions.

Spring Boot DevTools (recommended for development environment):

Spring Boot DevTools is a development tool provided by Spring Boot. It can automatically restart applications and automatically reload classes when code changes.

  • Add dependencies:

    <dependency>
        <groupId></groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <optional>true</optional>
    </dependency>
    
  • principle:

    • DevTools uses two class loaders:
      • base classloader:Load classes that will not change (for example, third-party libraries).
      • restart classloader:Load the class being developed.
    • When the code changes, DevTools discards the restart classloader and creates a new restart classloader to load the modified class.
    • Since the base classloader has not changed, the restart speed is very fast.
  • Triggering conditions:

    • By default, a restart is triggered when a file on the classpath changes.
    • Can be passedAttribute exclusion files that do not need to trigger restart.
    • Can be passed-pathsAttribute adds an additional path to trigger restart.
  • Disable automatic restart:

    • set up=falseAttributes.
    • use("", "false");
  • Notice:DevTools should not be used in production environments.

Which method to choose:

  • Development environment:It is recommended to use Spring Boot DevTools or the built-in hot deployment function of the IDE.
  • Production environment:It is generally not recommended to use hot deployment in production environments because it may cause unpredictable problems. If you really need it, you can use a more reliable solution, such as:
    • Blue-Green Deployment:Deploy the new version of the application to a new environment (green environment), and switch traffic to the new environment.
    • Rolling Update:Step updating the application's instances instead of updating all instances at once.
    • Canary Release:Deploy the new version of the application to a small number of users, and then gradually promote it to all users after the test is stable.
  • Special requirements:If more fine-grained control is required, or bytecode needs to be modified, you can use a custom class loader or Java Instrumentation API.

Summarize:

Java provides a variety of ways to implement hot loading and hot deployment, including custom class loaders, Java Instrumentation API, Spring Boot DevTools, and other tools. Which method to choose depends on the specific needs at development, in production environments, hot deployment is not usually recommended, but more reliable deployment strategies such as blue-green deployment, rolling updates, or canary releases.

This is the article about how to implement hot loading and hot deployment of classes in Java. For more related hot loading and hot deployment of Java classes, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!