Automatic Registration of Executors and JobHandlers for XXL-Job via a Spring Boot Starter
This article explains how to create a Spring Boot starter that automatically registers XXL-Job executors and job handlers to the scheduling center, eliminating manual configuration through code examples, API analysis, and step‑by‑step implementation details.
XXL-Job is a lightweight, distributed task scheduling middleware widely used in projects. Normally, each executor and job must be manually added through the XXL-Job admin UI, which becomes tedious when there are many tasks.
The goal is to avoid the admin page by automatically registering executors and job handlers at application startup.
Analysis
By inspecting the XXL-Job admin module, the key REST endpoints are identified:
/jobgroup/save – add executor
/jobgroup/pageList – query executors
/jobinfo/add – add job
/jobinfo/pageList – query jobs
/login – obtain authentication cookie
These endpoints require a login cookie ( XXL_JOB_LOGIN_IDENTITY ) obtained from the /login API.
Transformation
The starter adds the following Maven dependencies:
<dependency>
<groupId>com.xuxueli</groupId>
<artifactId>xxl-job-core</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>Login service obtains the cookie and caches it:
private final Map
loginCookie = new HashMap<>();
public void login(){
String url = adminAddresses + "/login";
HttpResponse response = HttpRequest.post(url)
.form("userName", username)
.form("password", password)
.execute();
List
cookies = response.getCookies();
Optional
cookieOpt = cookies.stream()
.filter(c -> c.getName().equals("XXL_JOB_LOGIN_IDENTITY"))
.findFirst();
if(!cookieOpt.isPresent())
throw new RuntimeException("get xxl-job cookie error!");
loginCookie.put("XXL_JOB_LOGIN_IDENTITY", cookieOpt.get().getValue());
}
public String getCookie(){
for(int i=0;i<3;i++){
String cookie = loginCookie.get("XXL_JOB_LOGIN_IDENTITY");
if(cookie != null) return "XXL_JOB_LOGIN_IDENTITY=" + cookie;
login();
}
throw new RuntimeException("get xxl-job cookie error!");
}Executor service checks existence and registers if needed:
public List
getJobGroup(){
String url = adminAddresses + "/jobgroup/pageList";
HttpResponse resp = HttpRequest.post(url)
.form("appname", appName)
.form("title", title)
.cookie(jobLoginService.getCookie())
.execute();
JSONArray arr = JSONUtil.parse(resp.body()).getByPath("data", JSONArray.class);
return arr.stream()
.map(o -> JSONUtil.toBean((JSONObject)o, XxlJobGroup.class))
.collect(Collectors.toList());
}
public boolean preciselyCheck(){
return getJobGroup().stream()
.anyMatch(g -> g.getAppname().equals(appName) && g.getTitle().equals(title));
}
public boolean autoRegisterGroup(){
String url = adminAddresses + "/jobgroup/save";
HttpResponse resp = HttpRequest.post(url)
.form("appname", appName)
.form("title", title)
.cookie(jobLoginService.getCookie())
.execute();
return JSONUtil.parse(resp.body()).getByPath("code").equals(200);
}Job service performs similar operations for job handlers, including creation of XxlJobInfo objects and adding them via /jobinfo/add .
Automatic Registration Core
A component implements ApplicationListener to trigger registration after the Spring context is ready:
@Component
public class XxlJobAutoRegister implements ApplicationListener
, ApplicationContextAware {
@Autowired private JobGroupService jobGroupService;
@Autowired private JobInfoService jobInfoService;
private ApplicationContext applicationContext;
@Override public void setApplicationContext(ApplicationContext ctx) { this.applicationContext = ctx; }
@Override public void onApplicationEvent(ApplicationReadyEvent event) {
addJobGroup(); // register executor
addJobInfo(); // register jobs
}
private void addJobGroup(){
if(jobGroupService.preciselyCheck()) return;
if(jobGroupService.autoRegisterGroup())
log.info("auto register xxl-job group success!");
}
private void addJobInfo(){
List
groups = jobGroupService.getJobGroup();
XxlJobGroup group = groups.get(0);
String[] beanNames = applicationContext.getBeanNamesForType(Object.class, false, true);
for(String name : beanNames){
Object bean = applicationContext.getBean(name);
Map
methods = MethodIntrospector.selectMethods(bean.getClass(),
method -> AnnotatedElementUtils.findMergedAnnotation(method, XxlJob.class));
for(Map.Entry
entry : methods.entrySet()){
Method m = entry.getKey();
XxlJob xxlJob = entry.getValue();
if(m.isAnnotationPresent(XxlRegister.class)){
XxlRegister reg = m.getAnnotation(XxlRegister.class);
List
existing = jobInfoService.getJobInfo(group.getId(), xxlJob.value());
if(!existing.isEmpty()){
Optional
match = existing.stream()
.filter(info -> info.getExecutorHandler().equals(xxlJob.value()))
.findFirst();
if(match.isPresent()) continue;
}
XxlJobInfo info = createXxlJobInfo(group, xxlJob, reg);
jobInfoService.addJobInfo(info);
}
}
}
}
}A custom annotation @XxlRegister is defined to carry cron expression, description, author, and trigger status:
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface XxlRegister {
String cron();
String jobDesc() default "default jobDesc";
String author() default "default Author";
int triggerStatus() default 0;
}Auto‑Configuration
A configuration class scans the package com.xxl.job.plus.executor and is registered via META-INF/spring.factories so that the starter is auto‑loaded.
Testing
After publishing the starter to a Maven repository, a new Spring Boot project adds the dependency, configures XXL‑Job properties (admin address, token, executor name, etc.), and annotates methods with both @XxlJob and @XxlRegister . When the application starts, the executor and the annotated jobs appear automatically in the XXL‑Job admin UI and can be triggered manually.
Conclusion
The complete source code is available on GitHub at https://github.com/trunks2008/xxl-job-auto-register . This starter saves developers time by removing repetitive manual registration steps.
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
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.