Backend Development 8 min read

Hot Deployment of Java Interface Implementations Using Reflection and Spring

This article demonstrates how to design a simple Calculator interface, provide both annotation‑based and reflection‑based implementations, and achieve hot deployment by loading user‑supplied JAR files at runtime, including dynamic bean registration and removal in a Spring container.

Java Architect Essentials
Java Architect Essentials
Java Architect Essentials
Hot Deployment of Java Interface Implementations Using Reflection and Spring

The article describes a scenario where a system allows users to upload a JAR containing an implementation of a predefined interface, and the system hot‑deploys and switches the implementation at runtime.

Interface definition

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

Implementation class shows two methods: calculate (annotation‑based) and add (reflection‑based), with Spring @Service annotation and an injected CalculatorCore.

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

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

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

CalculatorCore provides the actual addition logic.

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

Reflection‑based hot deployment loads the uploaded JAR with a URLClassLoader, obtains the implementation class by its fully‑qualified name, creates an instance, and invokes the method.

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

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

Spring‑based hot deployment scans all classes in the JAR, registers those annotated as Spring beans into the current BeanFactory, and thus makes them available in the container.

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());
        }
    }
}

Utility methods in DeployUtils include reading all class files from a JAR, checking whether a class carries Spring annotations, and converting a class name to a bean name.

public static Set
readJarFile(String jarAddress) throws IOException { ... }
public static boolean isSpringBeanClass(Class
cla) { ... }
public static String transformName(String className) { ... }

When a JAR is removed, the corresponding beans are also deregistered from the Spring container.

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

A test class demonstrates a loop that repeatedly attempts hot deployment, sleeping when the JAR is not yet present.

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

The article concludes with a call to share the content and join the community.

Javabackend developmentreflectionSpringdynamic loadingHot Deployment
Java Architect Essentials
Written by

Java Architect Essentials

Committed to sharing quality articles and tutorials to help Java programmers progress from junior to mid-level to senior architect. We curate high-quality learning resources, interview questions, videos, and projects from across the internet to help you systematically improve your Java architecture skills. Follow and reply '1024' to get Java programming resources. Learn together, grow together.

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.