Spring @Async метод порождает больше потоков: как сохранить контекст запроса - PullRequest
0 голосов
/ 05 июня 2018

В нашем приложении Spring возникает ситуация, когда мы используем несколько облачных конечных точек REST для извлечения данных, которые объединяются в один объект данных (назовем его Employee.java), который затем передается в бизнес-логику.

Я бы хотел инкапсулировать все эти вызовы в один метод служебного компонента, примерно так:

@Service
public class EmployeeService {

   public Employee retrieveEmployee(String id) {
      Employee e = new Employee();
      callRESTToFillWithBasicData(e);
      callRESTToFillWithExtendedData(e);
      callRESTToFillWithAdditionalData(e);
      return e;
   }
}

Поскольку вызовы REST довольно трудоемки, мы хотим сделать этот метод асинхроннымТаким образом, приложение может делать другие вещи в то же время.Для дополнительной сложности методам в службе необходим доступ к бинам Spring в области запроса.Проблема в том, что Spring по умолчанию не передает контекст запроса потокам, созданным с помощью асинхронных методов.Поэтому мы написали пользовательскую реализацию ThreadPoolTaskExecutor, похожую на то, что предлагается здесь .Асинхронный код выглядит следующим образом:

@Service
public class EmployeeService {

   @Async("requestAwareTaskExecutor")
   public CompletableFuture<Employee> retrieveEmployee(String id) {
      Employee e = new Employee();
      callRESTToFillWithBasicData(e);
      callRESTToFillWithExtendedData(e);
      callRESTToFillWithAdditionalData(e);
      return CompletableFuture.completedFuture(e);
   }
}

Теперь, чтобы ускорить процесс, мы также хотим распараллелить 3 вызова REST в методе.Это оставляет нам некоторые проблемы, которые нужно решить:

  • Проблема в том, что мы не можем просто поместить @Async в методы callRESTToFill..., потому что вызовы методов из одного объекта в себяне маршрутизируется через Spring-прокси и, следовательно, не выполняется асинхронно.

  • Мы также не можем просто обернуть вызовы методов в CompletableFuture.runAsync(...), потому что тогда потоки, опять же, не смогутbean-объекты в пределах запроса.

  • В крайнем случае можно было бы добавить компонент Executor с запросом @Autowired в компонент службы и передать его на все вызовы CompletableFuture.

Но мы не чувствуем, что это путь весны.Непосредственное использование Executor кажется излишним, учитывая, что мы уже указали bean-компонент executor в аннотации @Async.

Что было бы лучшим вариантом здесь?

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