2012-02-02 116 views
4

我有一个Spring-Batch作业,我从Spring MVC控制器启动。该控制器从用户获取上传的文件和作业应该处理文件:Spring批处理:从Spring MVC控制器启动一个作业WITH NEW THREAD

@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; 
} 

我尝试下面的XML配置:

<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> 

...但它似乎像多线程只发生在工作范围内。即,控制器线程一直等到作业结束,并且作业执行由多个线程处理(这是好的,但不是我想要的主要事情)。我想要的主要事情是作业将在单独的线程(或多个线程)上启动,而控制器线程将继续执行而不等待作业线程结束。

有没有办法用Spring-batch实现这一点?

回答

6

官方documentation说明您的具体问题,并在4.5.2. Running Jobs from within a Web Container一个解决方案:

[...]控制器启动使用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"> 
    <property name="jobRepository" ref="jobRepository" /> 
    <property name="taskExecutor" ref="taskExecutor"/> 
</bean> 

免责声明:我从来没有使用过春节批...

+0

谢谢!正是我想要的!初学者的运气:) – rapt 2012-02-02 15:32:48

+0

第二个链接是404,请更新正确的链接。 – Rembo 2015-01-13 07:37:43

1

如果您不需要向客户端显示处理错误,则可以在单独的线程中启动弹簧批处理作业。

+0

我在想它 - 但是在春季批量框架中是否有这样的设置?例如。假设我希望每个请求都为它的作业启动一个新线程,但最多只能有10个这样的线程 - 如果我现在有超过10个文件需要处理,那么只有10个文件会获得他们自己的新线程和其他文件将稍后处理,也许由一些全球调度程序处理。 Spring-batch开发人员是否已经实施(至少部分)? – rapt 2012-02-02 14:56:07

3

jobLauncher.run()方法可以被调用在一个新的Thread像这样:

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

    final SomeObject jobLauncher = [...] 
    Thread thread = new Thread(){ 
    @Override 
    public void run(){ 
     jobLauncher.run([...]); 
    } 
    }; 
    thread.start(); 

    return mav; 
} 

thread.start()线将产生一个新的线程,然后继续执行它下面的代码。

请注意,如果jobLauncher是局部变量,则必须将其声明为final以便在匿名Thread类中使用它。

相关问题