Backend Development 17 min read

Dynamic Loading and Unloading of Data Governance Tasks in Java with Custom ClassLoader and XXL‑Job Integration

This article explains how to implement dynamic loading, upgrading, and unloading of data‑governance tasks in a Java Spring application using a custom URLClassLoader, integrate the tasks with the XXL‑Job scheduler, manage Spring bean registration, and persist configuration changes via local YAML or Nacos.

Code Ape Tech Column
Code Ape Tech Column
Code Ape Tech Column
Dynamic Loading and Unloading of Data Governance Tasks in Java with Custom ClassLoader and XXL‑Job Integration

Overview

The data‑governance service currently requires a full restart whenever a governance task is added, upgraded, or removed, which disrupts other tasks. The goal is to enable dynamic start/stop, upgrade, and addition of tasks without affecting the rest of the system.

Solution

Load business functions as plug‑in JARs using a custom class loader.

Register each task as an XXL‑Job job for unified management.

Dynamic Loading

A custom class loader extending URLClassLoader is created to load external JARs at runtime and keep a map of loaded classes for later unloading.

package cn.jy.sjzl.util;

import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 自定义类加载器
 * @author lijianyu
 * @date 2023/04/03 17:54
 */
public class MyClassLoader extends URLClassLoader {
    private Map
> loadedClasses = new ConcurrentHashMap<>();
    public Map
> getLoadedClasses() { return loadedClasses; }
    public MyClassLoader(URL[] urls, ClassLoader parent) { super(urls, parent); }
    @Override
    protected Class
findClass(String name) throws ClassNotFoundException {
        Class
clazz = loadedClasses.get(name);
        if (clazz != null) { return clazz; }
        try {
            clazz = super.findClass(name);
            loadedClasses.put(name, clazz);
            return clazz;
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
            return null;
        }
    }
    public void unload() {
        try {
            for (Map.Entry
> entry : loadedClasses.entrySet()) {
                String className = entry.getKey();
                loadedClasses.remove(className);
                try {
                    Method destory = entry.getValue().getDeclaredMethod("destory");
                    destory.invoke(entry.getValue());
                } catch (Exception e) { /* ignore */ }
            }
            close();
        } catch (Exception e) { e.printStackTrace(); }
    }
}

The loader reads the JAR, registers any classes annotated with Spring stereotypes into the Spring ApplicationContext , and registers methods annotated with @XxlJob as job handlers.

package com.jy.dynamicLoad;

import com.jy.annotation.XxlJobCron;
import com.jy.classLoader.MyClassLoader;
import com.xxl.job.core.executor.impl.XxlJobSpringExecutor;
import com.xxl.job.core.handler.annotation.XxlJob;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

@Component
public class DynamicLoad {
    @Autowired private ApplicationContext applicationContext;
    private Map
myClassLoaderCenter = new ConcurrentHashMap<>();
    @Value("${dynamicLoad.path}") private String path;
    public void loadJar(String path, String fileName, Boolean isRegistXxlJob) throws Exception {
        // load JAR, create MyClassLoader, register Spring beans and XXL‑Job handlers
    }
    // ... other methods omitted for brevity
}

Dynamic Unloading

Unloading removes the JAR’s classes from the custom class loader, deregisters the beans from Spring, and removes the job handlers from the XXL‑Job executor.

public void unloadJar(String fileName) throws IllegalAccessException, NoSuchFieldException {
    MyClassLoader myClassLoader = myClassLoaderCenter.get(fileName);
    // remove job handlers from XXL‑Job executor
    // destroy Spring beans and bean definitions
    // clear classes from the class loader and close it
}

Dynamic Configuration

Two approaches are provided to persist the list of loaded JARs:

Modify a local bootstrap.yml file using SnakeYAML.

Update a Nacos configuration file ( sjzl‑loadjars.yml ) via the Nacos Java SDK.

Both utilities read the existing configuration, add the new JAR name if absent, and write the updated configuration back to the source.

Packaging

The article also shows a Maven shade plugin configuration to produce a fat JAR that includes the dynamically loaded code.

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-shade-plugin</artifactId>
            <version>3.2.4</version>
            <executions>
                <execution>
                    <phase>package</phase>
                    <goals><goal>shade</goal></goals>
                    <configuration>
                        <filters>
                            <filter>
                                <artifact>*:*</artifact>
                                <includes><include>com/jy/job/demo/**</include></includes>
                            </filter>
                        </filters>
                        <finalName>demoJob</finalName>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

Finally, the author adds a promotional note encouraging readers to like, share, and join a knowledge community.

JavaBackend DevelopmentSpringNacosxxl-jobDynamic Class Loading
Code Ape Tech Column
Written by

Code Ape Tech Column

Former Ant Group P8 engineer, pure technologist, sharing full‑stack Java, job interview and career advice through a column. Site: java-family.cn

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.