You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot 3模块化上下文批处理应用指定任务无法启动

Spring Boot 3模块化批处理指定任务无法启动问题

问题描述

升级到Spring Boot 3后,通过参数--spring.batch.job.names指定批处理任务时,任务完全无法启动。执行命令java -jar mybatchapplication.jar --spring.batch.job.names=jobA后,应用启动完成后直接关闭,尝试--spring.batch.job.name参数也无效。

核心代码

主类

@SpringBootApplication
@EnableJpaRepositories("path.to.my.repositories")
@EntityScan("path.to.my.entities")
public class MyBatchApplication{
    public static void main(String[] args) {
        System.exit(SpringApplication.exit(SpringApplication.run(MyBatchApplication.class, args)));
    }
}

模块化配置类

@Configuration
@EnableBatchProcessing(modular = true)
public class MyModularBatchJobContextConfiguration {
    @Bean
    ApplicationContextFactory getJobAContext() {
        return new GenericApplicationContextFactory(JobAConfig.class);
    }

    @Bean
    ApplicationContextFactory getJobBContext() {
        return new GenericApplicationContextFactory(JobBConfig.class);
    }
}

任务配置类(JobAConfig示例)

public class JobAConfig {

    private static final String MY_JOB_NAME = "jobA";

    @Autowired
    private EntityManagerFactory emf;

    @Bean
    public Job jobA(JobRepository jobRepository, Step myStep) {
        return new JobBuilder(MY_JOB_NAME, jobRepository)
                .flow(myStep)
                .end()
                .build();
    }

    @Bean
    public Step myStep(JpaTransactionManager transactionManager,
                       JobRepository jobRepository,
                       FlatFileItemReader<MyEntity> reader,
                       ItemProcessor<MyEntity, MyEntity> processor,
                       JpaItemWriter<MyEntity> entityWriter) {
        return new StepBuilder(MY_STEP_NAME, jobRepository)
                .<MyEntity, MyEntity>chunk(10, transactionManager)
                .reader(reader)
                .processor(processor)
                .writer(entityWriter)
                .transactionManager(transactionManager)
                .build();
    }

// Reader, Writer, Processor...
}

日志信息

2023-05-11T22:05:21.823+02:00  INFO 9716 --- [           main] d.f.r.batch.MyBatchApplication: Starting MyBatchApplicationusing Java 17.0.5 with PID 9716 (C:\gits\mygit\batch\target\mybatchapplication.jar started by me in C:\gits\mygit)
2023-05-11T22:05:21.825+02:00  INFO 9716 --- [           main] d.f.r.batch.MyBatchApplication: No active profile set, falling back to 1 default profile: "default"
2023-05-11T22:05:22.112+02:00  INFO 9716 --- [           main] o.s.b.c.c.annotation.BatchRegistrar      : Finished Spring Batch infrastructure beans configuration in 6 ms.
2023-05-11T22:05:22.118+02:00  INFO 9716 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data JPA repositories in DEFAULT mode.
2023-05-11T22:05:22.149+02:00  INFO 9716 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 25 ms. Found 2 JPA repository interfaces.
2023-05-11T22:05:22.571+02:00  INFO 9716 --- [           main] o.hibernate.jpa.internal.util.LogHelper  : HHH000204: Processing PersistenceUnitInfo [name: default]
2023-05-11T22:05:22.616+02:00  INFO 9716 --- [           main] org.hibernate.Version                    : HHH000412: Hibernate ORM core version 6.1.7.Final
2023-05-11T22:05:22.895+02:00  INFO 9716 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting...
2023-05-11T22:05:22.995+02:00  INFO 9716 --- [           main] com.zaxxer.hikari.pool.PoolBase          : HikariPool-1 - Driver does not support get/set network timeout for connections. (Receiver class org.h2.jdbc.JdbcConnection does not define or inherit an implementation of the resolved method 'abstract int getNetworkTimeout()' of interface java.sql.Connection.)
2023-05-11T22:05:22.998+02:00  INFO 9716 --- [           main] com.zaxxer.hikari.pool.HikariPool        : HikariPool-1 - Added connection conn0: url=jdbc:h2:file:~/mydb user=SA
2023-05-11T22:05:22.999+02:00  INFO 9716 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.
2023-05-11T22:05:23.016+02:00  INFO 9716 --- [           main] SQL dialect                              : HHH000400: Using dialect: org.hibernate.dialect.H2Dialect
2023-05-11T22:05:23.542+02:00  INFO 9716 --- [           main] o.h.e.t.j.p.i.JtaPlatformInitiator       : HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform]
2023-05-11T22:05:23.552+02:00  INFO 9716 --- [           main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
2023-05-11T22:05:23.588+02:00  INFO 9716 --- [           main] o.s.b.c.r.s.JobRepositoryFactoryBean     : No database type set, using meta data indicating: H2
2023-05-11T22:05:23.613+02:00  INFO 9716 --- [           main] o.s.b.c.l.support.SimpleJobLauncher      : No TaskExecutor has been set, defaulting to synchronous executor.
2023-05-11T22:05:24.294+02:00  WARN 9716 --- [           main] o.s.b.c.l.AbstractListenerFactoryBean    : org.springframework.batch.item.ItemProcessor is an interface. The implementing class will not be queried for annotation based listener configurations. If using @StepScope on a @Bean method, be sure to return the implementing class so listener annotations can be used.
2023-05-11T22:05:24.322+02:00  INFO 9716 --- [           main] .c.a.BatchObservabilityBeanPostProcessor : No Micrometer observation registry found, defaulting to ObservationRegistry.NOOP
2023-05-11T22:05:24.358+02:00  INFO 9716 --- [           main] .c.a.BatchObservabilityBeanPostProcessor : No Micrometer observation registry found, defaulting to ObservationRegistry.NOOP
2023-05-11T22:05:24.370+02:00  WARN 9716 --- [           main] o.s.b.c.l.AbstractListenerFactoryBean    : org.springframework.batch.item.ItemProcessor is an interface. The implementing class will not be queried for annotation based listener configurations. If using @StepScope on a @Bean method, be sure to return the implementing class so listener annotations can be used.
2023-05-11T22:05:24.371+02:00  INFO 9716 --- [           main] .c.a.BatchObservabilityBeanPostProcessor : No Micrometer observation registry found, defaulting to ObservationRegistry.NOOP
2023-05-11T22:05:24.371+02:00  INFO 9716 --- [           main] .c.a.BatchObservabilityBeanPostProcessor : No Micrometer observation registry found, defaulting to ObservationRegistry.NOOP
2023-05-11T22:05:24.395+02:00  INFO 9716 --- [           main] d.f.r.batch.MyBatchApplication: Started MyBatchApplicationin 2.848 seconds (process running for 3.242)
2023-05-11T22:05:24.406+02:00  INFO 9716 --- [           main] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default'
2023-05-11T22:05:24.410+02:00  INFO 9716 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown initiated...
2023-05-11T22:05:24.417+02:00  INFO 9716 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown completed.

问题原因

在Spring Boot 3 + Spring Batch的模块化配置中,--spring.batch.job.names参数默认只会扫描主ApplicationContext中的Job bean,而你的JobA、JobB都在通过GenericApplicationContextFactory创建的子ApplicationContext里,主上下文无法直接找到这些Job,导致批处理自动启动逻辑不触发,应用启动后直接关闭。

解决方法

方法一:使用子上下文前缀指定任务名

模块化批处理中,子上下文的Job bean会自动带上子上下文ID作为前缀,默认前缀是配置类的全限定名(比如path.to.JobAConfig)。你需要用前缀.任务名的形式指定:

java -jar mybatchapplication.jar --spring.batch.job.names=path.to.JobAConfig.jobA

或者给GenericApplicationContextFactory自定义ID,简化前缀:

@Bean
ApplicationContextFactory getJobAContext() {
    return new GenericApplicationContextFactory(JobAConfig.class).setId("jobAContext");
}

之后用自定义ID作为前缀:

java -jar mybatchapplication.jar --spring.batch.job.names=jobAContext.jobA

方法二:自定义JobLocator扫描所有子上下文

自定义JobLocator来统一管理所有子上下文的Job,让批处理自动配置能找到这些任务:

@Configuration
@EnableBatchProcessing(modular = true)
public class MyModularBatchJobContextConfiguration {
    @Bean
    ApplicationContextFactory getJobAContext() {
        return new GenericApplicationContextFactory(JobAConfig.class);
    }

    @Bean
    ApplicationContextFactory getJobBContext() {
        return new GenericApplicationContextFactory(JobBConfig.class);
    }

    @Bean
    public JobLocator jobLocator(List<ApplicationContextFactory> contextFactories) {
        ModularJobLocator modularJobLocator = new ModularJobLocator();
        modularJobLocator.setApplicationContextFactories(contextFactories);
        return modularJobLocator;
    }
}

方法三:手动实现任务触发

通过CommandLineRunner手动解析命令行参数,遍历子上下文查找并启动指定任务:

@Component
public class BatchJobRunner implements CommandLineRunner {
    private final JobLauncher jobLauncher;
    private final List<ApplicationContextFactory> contextFactories;

    public BatchJobRunner(JobLauncher jobLauncher, List<ApplicationContextFactory> contextFactories) {
        this.jobLauncher = jobLauncher;
        this.contextFactories = contextFactories;
    }

    @Override
    public void run(String... args) throws Exception {
        String jobNames = Arrays.stream(args)
                .filter(arg -> arg.startsWith("--spring.batch.job.names="))
                .map(arg -> arg.split("=", 2)[1])
                .findFirst()
                .orElse(null);

        if (jobNames == null) {
            return;
        }

        for (String jobName : jobNames.split(",")) {
            for (ApplicationContextFactory factory : contextFactories) {
                ApplicationContext context = factory.createApplicationContext();
                if (context.containsBean(jobName)) {
                    Job job = context.getBean(jobName, Job.class);
                    jobLauncher.run(job, new JobParameters());
                    break;
                }
            }
        }
    }
}

内容的提问来源于stack exchange,提问作者Manu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 22:27:00