My [basic] Spring Загрузочное приложение принимает запрос от браузера, отправленный через jQuery.get()
и должен немедленно получать ответ - например, "ваш запрос был поставлен в очередь". Для этого я написал контроллер:
@Controller
public class DoSomeWorkController {
@Autowired
private final DoWorkService workService;
@RequestMapping("/doSomeWork")
@ResponseBody
public String doSomeWork() {
workService.doWork(); // time consuming operation
return "Your request has been queued.";
}
}
Класс DoWorkServiceImpl
реализует интерфейс DoWorkService
и действительно прост. Он имеет единственный способ выполнения трудоемкой задачи. Мне не нужно что-либо, возвращенное из этого служебного вызова, поскольку электронное письмо будет доставлено в конце работы, как для сценариев сбоя, так и для успеха. Таким образом, это будет выглядеть так:
@Service
public class DoWorkServiceImpl implements DoWorkService {
@Async("workExecutor")
@Override
public void doWork() {
try {
Thread.sleep(10 * 1000);
System.out.println("completed work, sent email");
}
catch (InterruptedException ie) {
System.err.println(ie.getMessage());
}
}
}
Я думал, что это сработает, но браузер Ajax-запрос ждал 10 секунд, прежде чем возвращать ответ. Таким образом, метод сопоставления с контроллером вызывает синхронный внутренний метод, аннотированный с помощью @Async
. В традиционном приложении Spring я обычно добавляю это в конфигурацию XML:
<task:annotation-driven />
<task:executor id="workExecutor" pool-size="1" queue-capacity="0" rejection-policy="DISCARD" />
Итак, я подумал, что написать эквивалент этого в главном классе приложения поможет:
@SpringBootApplication
@EnableAsync
public class Application {
@Value("${pool.size:1}")
private int poolSize;;
@Value("${queue.capacity:0}")
private int queueCapacity;
@Bean(name="workExecutor")
public TaskExecutor taskExecutor() {
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
taskExecutor.setMaxPoolSize(poolSize);
taskExecutor.setQueueCapacity(queueCapacity);
taskExecutor.afterPropertiesSet();
return taskExecutor;
}
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Это не изменило поведение. Ответ Ajax по-прежнему поступает через 10 секунд после отправки запроса. Что мне не хватает?
Приложение Spring для загрузки может быть загружено здесь. Если Maven установлен, проект можно запустить с помощью простой команды:
mvn clean spring-boot:run
Примечание Проблема была решена благодаря ответу, предоставленному ниже @Dave Syer, который указал, что мне не хватает @EnableAsync
в моем приложении, хотя у меня была строка в фрагменте кода выше.