且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

Spring Batch:从一个带有新线程的Spring MVC控制器中启动一个作业

更新时间:2023-09-07 21:43:16

官方文档描述了您的确切问题以及 4.5.2。从Web容器中运行作业


[...]控制器使用 JobLauncher ,会立即返回 JobExecution 。作业可能仍在运行,但是,这种非阻塞行为允许控制器立即返回,这在处理HttpRequest时是必需的。


Spring Batch http://static.springsource.org/spring-batch/reference/html-single/images/launch-from-request.png



所以你非常接近尝试使用 TaskExecutor ,但是它需要传递给 JobLauncher 而不是:

 < bean id =jobLauncher
class =org.springframework.batch.core.launch.support.SimpleJobLauncher &GT;
< property name =jobRepositoryref =jobRepository/>
< property name =taskExecutorref =taskExecutor/>
< / bean>

免责声明:我从未使用过Spring Batch ...


I have a Spring-Batch job that I launch from a Spring MVC controller. The controller gets an uploaded file from the user and the job is supposed to process the file:

@RequestMapping(value = "/upload")
public ModelAndView uploadInventory(UploadFile uploadFile, BindingResult bindingResult) {

    // code for saving the uploaded file to disk goes here...

    // now I want to launch the job of reading the file line by line and saving it to the database,
    // but I want to launch this job in a new thread, not in the HTTP request thread,
    // since I so not want the user to wait until the job ends.
    jobLauncher.run(
                    jobRegistry.getJob(JOB_NAME),
                    new JobParametersBuilder().addString("targetDirectory", folderPath).addString("targetFile", fileName).toJobParameters()
                    );

    return mav;
}

I've tried the following XML config:

<job id="writeProductsJob" xmlns="http://www.springframework.org/schema/batch">
    <step id="readWrite">
        <tasklet task-executor="taskExecutor">
            <chunk reader="productItemReader" writer="productItemWriter" commit-interval="10" />
        </tasklet>
    </step>
</job>

<bean id="taskExecutor"
    class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
    <property name="corePoolSize" value="5" />
    <property name="maxPoolSize" value="5" />
</bean>

...but it seems like the multithreading happens only within the job boundaries itself. I.e., the controller thread waits until the job ends, and the job execution is handled by multiple threads (which is good but not the main thing I wanted). The main thing I wanted is that the job will be launched on a separate thread (or threads) while the controller thread will continue its execution without waiting for the job threads to end.

Is there a way to achieve this with Spring-batch?

The official documentation describes your exact problem and a solution in 4.5.2. Running Jobs from within a Web Container:

[...] The controller launches a Job using a JobLauncher that has been configured to launch asynchronously, which immediately returns a JobExecution. The Job will likely still be running, however, this nonblocking behaviour allows the controller to return immediately, which is required when handling an HttpRequest.

Spring Batch http://static.springsource.org/spring-batch/reference/html-single/images/launch-from-request.png

So you were pretty close in trying to use TaskExecutor, however it needs to be passed to the JobLauncher instead:

<bean id="jobLauncher"
      class="org.springframework.batch.core.launch.support.SimpleJobLauncher">
    <property name="jobRepository" ref="jobRepository" />
    <property name="taskExecutor" ref="taskExecutor"/>
</bean>

Disclaimer: I have never used Spring Batch...