Spring Batch: запуск задания из контроллера Spring MVC С НОВОЙ РЕЗЬБОЙ - PullRequest
4 голосов
/ 02 февраля 2012

У меня есть задание Spring-Batch, которое я запускаю с контроллера Spring MVC. Контроллер получает загруженный файл от пользователя, и задание должно обрабатывать файл:

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

Ответы [ 3 ]

6 голосов
/ 02 февраля 2012

Официальная документация описывает вашу точную проблему и решение в 4.5.2. Запуск заданий из веб-контейнера :

[...] Контроллер запускает задание, используя JobLauncher, который был настроен для асинхронного запуска , что немедленно возвращает JobExecution. Задание, вероятно, все еще будет работать, однако это неблокирующее поведение позволяет контроллеру немедленно возвращать , что требуется при обработке запроса HttpRequest.

Пружинная партия 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>

Отказ от ответственности: Я никогда не использовал Spring Batch ...

3 голосов
/ 02 февраля 2012

Метод 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.

1 голос
/ 02 февраля 2012

Если вам не нужно показывать ошибки обработки вашему клиенту, вы можете запустить пакетное задание пружины в отдельном потоке.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...