Backend Development 15 min read

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.

Code Ape Tech Column
Code Ape Tech Column
Code Ape Tech Column
Automatic Registration of Executors and JobHandlers for XXL-Job via a Spring Boot Starter

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.

Javatask schedulingSpring Bootauto-registrationxxl-jobStarter
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.