Why Manual JAR Deployment Is Outdated and How Dynamic Hot‑Deploy Makes It Easy
This article walks through defining a simple Calculator interface, provides two implementation styles, and demonstrates both reflection‑based and annotation‑based hot‑deployment of uploaded JARs in a Spring application, including bean registration, removal, and a test loop.
Define a Simple Interface
Example of a Calculator interface with calculate and add methods.
public interface Calculator {
int calculate(int a, int b);
int add(int a, int b);
}Simple Implementation
Two implementations: annotation‑based (managed by Spring) and reflection‑based.
@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
@Service
public class CalculatorCore {
public int add(int a, int b) {
return a + b;
}
}Reflection‑Based Hot Deployment
Upload JAR path, load with URLClassLoader, instantiate class, invoke add.
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);
}Annotation‑Based Hot Deployment
Load JAR, scan classes, register beans whose classes carry Spring stereotypes.
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());
}
}
}Removing Beans When JAR Is Deleted
Iterate classes, if Spring bean, remove its definition from the same BeanFactory.
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));
}
}
}DeployUtils Helper Methods
Methods to read all class names from a JAR, check for Spring annotations, and convert class names to bean IDs.
public static Set<String> readJarFile(String jarAddress) throws IOException {
Set<String> classNameSet = new HashSet<>();
JarFile jarFile = new JarFile(jarAddress);
Enumeration<JarEntry> entries = jarFile.entries();
while (entries.hasMoreElements()) {
JarEntry jarEntry = entries.nextElement();
String name = jarEntry.getName();
if (name.endsWith(".class")) {
String className = name.replace(".class", "").replaceAll("/", ".");
classNameSet.add(className);
}
}
return classNameSet;
}
public static boolean isSpringBeanClass(Class<?> cla) {
if (cla == null || cla.isInterface() || Modifier.isAbstract(cla.getModifiers())) {
return false;
}
return cla.getAnnotation(Component.class) != null ||
cla.getAnnotation(Repository.class) != null ||
cla.getAnnotation(Service.class) != null;
}
public static String transformName(String className) {
String tmpstr = className.substring(className.lastIndexOf(".") + 1);
return tmpstr.substring(0, 1).toLowerCase() + tmpstr.substring(1);
}Test Loop
Continuously attempts hot deployment; if the JAR is not found, catches the exception, waits ten seconds, then retries.
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);
}
}Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Java Tech Enthusiast
Sharing computer programming language knowledge, focusing on Java fundamentals, data structures, related tools, Spring Cloud, IntelliJ IDEA... Book giveaways, red‑packet rewards and other perks await!
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.
