How to Hot-Deploy Custom Java Interfaces with Spring and Reflection

This article demonstrates how to define a simple Calculator interface, implement it via both Spring-managed and reflection-based approaches, and achieve hot deployment by uploading JAR files, dynamically loading classes, registering or deregistering beans in the Spring container, and testing the process.

Java High-Performance Architecture
Java High-Performance Architecture
Java High-Performance Architecture
How to Hot-Deploy Custom Java Interfaces with Spring and Reflection

Define a Simple Interface

Using a calculator example, the interface is defined as:

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

A Simple Implementation

The implementation supports two modes: an annotation‑based mode managed by Spring and a reflection‑based mode that does not depend on Spring.

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

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

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

The CalculatorCore class provides the actual addition logic:

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

Hot Deployment with Reflection

After a user uploads a JAR to a predefined directory, the system loads the JAR using a URLClassLoader, obtains the implementation class by its fully‑qualified name, creates an instance via reflection, and invokes the add method.

/** Hot‑load Calculator implementation using 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);
}

Hot Deployment with Spring

If the uploaded JAR contains Spring components, the system scans all classes, registers those annotated with @Component, @Service, or @Repository as beans in the current Spring container.

/** Register beans from uploaded JAR into Spring */
public static void hotDeployWithSpring() throws Exception {
    Set<String> 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());
        }
    }
}

Utility methods used:

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

/** Determine whether a class is a Spring bean */
public static boolean isSpringBeanClass(Class<?> cla) { ... }

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

Removing Beans When Deleting a JAR

When a JAR is removed or replaced, the previously registered beans must be deregistered from the Spring container using the same bean names.

/** Delete beans registered from a JAR */
public static void delete() throws Exception {
    Set<String> 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));
        }
    }
}

Test Example

A test loop continuously attempts hot deployment, catching exceptions until the JAR becomes available.

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);
    }
}
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaReflectionDynamic LoadingHot Deployment
Java High-Performance Architecture
Written by

Java High-Performance Architecture

Sharing Java development articles and resources, including SSM architecture and the Spring ecosystem (Spring Boot, Spring Cloud, MyBatis, Dubbo, Docker), Zookeeper, Redis, architecture design, microservices, message queues, Git, etc.

0 followers
Reader feedback

How this landed with the community

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.