Hot Deployment of Custom Interface Implementations in Java Using Reflection and Spring
This article demonstrates how to define a simple Calculator interface, provide both annotation‑based and reflection‑based implementations, and dynamically hot‑deploy user‑supplied JAR files by loading them with URLClassLoader, registering Spring beans, and handling bean removal on JAR deletion.
Define Simple Interface
First, a Calculator interface with calculate and add methods is defined.
public interface Calculator {
int calculate(int a, int b);
int add(int a, int b);
}Implementation Class
The implementation provides two ways: annotation‑based ( calculate ) and reflection‑based ( add ). It injects CalculatorCore to demonstrate bean dependency construction.
@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
Simple component providing the add operation.
@Service
public class CalculatorCore {
public int add(int a, int b) {
return a + b;
}
}Reflection‑Based Hot Deployment
Upload a JAR to a predefined directory, load it with URLClassLoader , obtain the implementation class by name, instantiate it via reflection, and invoke 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
If the uploaded JAR contains Spring components, scan all classes, register beans whose classes carry @Component , @Service , or @Repository annotations into the current Spring 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
DeployUtils provides methods to read all class entries from a JAR, determine whether a class is a Spring bean, and transform class names to bean IDs.
public static Set
readJarFile(String jarAddress) throws IOException { /* ... */ }
public static boolean isSpringBeanClass(Class
cla) { /* ... */ }
public static String transformName(String className) { /* ... */ }Bean Removal on JAR Deletion
When a JAR is removed, the previously registered 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));
}
}
}Test Harness
A simple loop 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);
}
}Architecture Digest
Focusing on Java backend development, covering application architecture from top-tier internet companies (high availability, high performance, high stability), big data, machine learning, Java architecture, and other popular fields.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.