Backend Development 8 min read

Hot Deployment of Java Interface Implementations Using Reflection and Spring

This article explains how to let users upload a JAR that implements a predefined Java interface, then dynamically load, register, and switch the implementation at runtime using both reflection‑based and Spring‑annotation‑based hot‑deployment techniques, complete with code examples and utility methods.

Selected Java Interview Questions
Selected Java Interview Questions
Selected Java Interview Questions
Hot Deployment of Java Interface Implementations Using Reflection and Spring

During development a system may require a user‑provided implementation of a given interface; the user packages the implementation into a JAR, uploads it, and the system hot‑deploys the new implementation without restarting.

Define a simple interface – the example uses a Calculator interface with int calculate(int a, int b) and int add(int a, int b) methods:

public interface Calculator {
    int calculate(int a, int b);
    int add(int a, int b);
}

Implementation class – two approaches are shown: an annotation‑based method ( calculate ) and a reflection‑based method ( add ). The class injects CalculatorCore and implements both methods.

@Service
public class CalculatorImpl implements Calculator {
    @Autowired
    CalculatorCore calculatorCore;

    /** Annotation‑based */
    @Override
    public int calculate(int a, int b) {
        int c = calculatorCore.add(a, b);
        return c;
    }

    /** Reflection‑based */
    @Override
    public int add(int a, int b) {
        return new CalculatorCore().add(a, b);
    }
}

The supporting CalculatorCore simply returns the sum of two integers:

@Service
public class CalculatorCore {
    public int add(int a, int b) {
        return a + b;
    }
}

Reflection‑based hot deployment – the uploaded JAR path is defined, then the JAR is loaded with a URLClassLoader , the implementation class is instantiated via reflection, and its method is invoked:

private static String jarAddress = "E:/zzq/IDEA_WS/CalculatorTest/lib/Calculator.jar";
private static String jarPath = "file:/" + jarAddress;

/** Hot load Calculator implementation via reflection */
public static void hotDeployWithReflect() throws Exception {
    URLClassLoader urlClassLoader = new URLClassLoader(new URL[]{new URL(jarPath)}, Thread.currentThread().getContextClassLoader());
    Class clazz = urlClassLoader.loadClass("com.nci.cetc15.calculator.impl.CalculatorImpl");
    Calculator calculator = (Calculator) clazz.newInstance();
    int result = calculator.add(1, 2);
    System.out.println(result);
}

Annotation‑based hot deployment – if the uploaded JAR contains Spring components, the system scans all classes, identifies those with Spring annotations, and registers them into the current Spring container dynamically:

/** Register beans from uploaded JAR into Spring */
public static void hotDeployWithSpring() throws Exception {
    Set
classNameSet = DeployUtils.readJarFile(jarAddress);
    URLClassLoader urlClassLoader = new URLClassLoader(new URL[]{new URL(jarPath)}, Thread.currentThread().getContextClassLoader());
    for (String className : classNameSet) {
        Class clazz = urlClassLoader.loadClass(className);
        if (DeployUtils.isSpringBeanClass(clazz)) {
            BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(clazz);
            defaultListableBeanFactory.registerBeanDefinition(DeployUtils.transformName(className), beanDefinitionBuilder.getBeanDefinition());
        }
    }
}

The utility class DeployUtils provides three methods:

/** Read all class files from a JAR */
public static Set
readJarFile(String jarAddress) throws IOException { ... }

/** Determine whether a class has a Spring stereotype annotation */
public static boolean isSpringBeanClass(Class
cla) { ... }

/** Convert the class name to a bean name (lower‑case first letter) */
public static String transformName(String className) { ... }

Removing a JAR – when a JAR is deleted or replaced, the previously registered Spring beans must be removed from the container using the same bean names:

/** Delete beans of an uploaded JAR from Spring */
public static void delete() throws Exception {
    Set
classNameSet = DeployUtils.readJarFile(jarAddress);
    URLClassLoader urlClassLoader = new URLClassLoader(new URL[]{new URL(jarPath)}, Thread.currentThread().getContextClassLoader());
    for (String className : classNameSet) {
        Class clazz = urlClassLoader.loadClass(className);
        if (DeployUtils.isSpringBeanClass(clazz)) {
            defaultListableBeanFactory.removeBeanDefinition(DeployUtils.transformName(className));
        }
    }
}

Testing – a test loop continuously attempts to hot‑deploy the JAR; if the JAR is not yet present, an exception is caught and the thread sleeps, allowing the developer to place the JAR in the designated directory.

ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) applicationContext.getAutowireCapableBeanFactory();
while (true) {
    try {
        hotDeployWithReflect();
        // hotDeployWithSpring();
        // delete();
    } catch (Exception e) {
        e.printStackTrace();
        Thread.sleep(1000 * 10);
    }
}

Source: https://blog.csdn.net/zhangzhiqiang_0912

backendJavareflectionSpringdynamic loadingHot Deployment
Selected Java Interview Questions
Written by

Selected Java Interview Questions

A professional Java tech channel sharing common knowledge to help developers fill gaps. Follow us!

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.