Передайте данные области запроса асинхронным методам в CDI

Приложение Java EE 7 работает на Wildfly 9.0.2.Final. Существует проблема с доступом к данным области запроса из методов @Asynchronous.

В веб-фильтре данные (например, токен) устанавливаются в bean-компонент RequestScoped CDI. Позже мы хотим получить доступ к этим данным. Все отлично работает, если мы работаем в одном потоке. Но если есть необходимость запускать код асинхронно, возникает проблема. CDI вводит пустой bean-компонент, и данные запроса теряются.

Вот пример:

@RequestScoped
public class CurrentUserService implements Serializable {
  public String token;
}

@Stateless
public class Service {
   @Inject
   private RestClient client;

    @Resource
    private ManagedExecutorService executorService;

    @Resource
    private ContextService contextService;

    @Asynchronous
    private <T> Future<T> getFuture(Supplier<T> supplier) {
        Callable<T> task = supplier::get;
        Callable<T> callable = contextService.createContextualProxy(task, Callable.class);
        return executorService.submit(callable);
    }

   public String getToken() throws Exception {
      return getFuture(client::getToken).get();
   }
}

@ApplicationScoped
public class RestClient {
    @Inject
    private CurrentUserService currentUserBean;

    public String getToken() {
        return currentUserBean.token;
    }
}

В данном примере мы хотим получить доступ к токену текущего пользователя (CurrentUserService#token) из асинхронного метода Service.getToken. В результате получим null.

Ожидается, что данные "области запроса" должны быть доступны из задач, выполняемых в области запроса. Что-то вроде InheritableThreadLocal следует использовать, чтобы разрешить доступ к исходным данным потока из новых потоков.

Это ошибка? Может я что-то не так делаю? Если да, то как правильно распространять такие данные в асинхронные вызовы?

Заранее спасибо.


person Iaroslav Savytskyi    schedule 22.12.2015    source источник
comment
Кроме того, у вас есть bean-компонент RequestScoped внутри ApplicationScoped. Вместо этого вы можете использовать @Inject Instance<CurrentUserService> currentUserBean.   -  person jpkrohling    schedule 22.12.2015
comment
@Гимби, ты прав. Вполне возможно, что новые темы будут жить дольше, чем исходные. Как видите, я обернул вызов прокси-сервером ContextService. Я ожидал, что прокси предоставит необходимую контекстную информацию. В любом случае, как решить проблему? Мне нужно получить доступ к данным запроса из нового потока. Можно как-то пройти?   -  person Iaroslav Savytskyi    schedule 22.12.2015
comment
@jpkrohling, спасибо. Я пробовал, но безуспешно :(   -  person Iaroslav Savytskyi    schedule 22.12.2015
comment
Ваш метод Service.getToken() принципиально синхронен. Он вызывает get для будущего, которое будет блокироваться до тех пор, пока будущее не будет выполнено. Так что весь этот асинхронный механизм, который у вас есть, все равно ничего не сделает.   -  person Steve C    schedule 23.12.2015
comment
@ Стив С, это только пример.   -  person Iaroslav Savytskyi    schedule 23.12.2015


Ответы (1)


Согласно §2.3.2.1 спецификации Java EE Concurrency Utilities не следует пытаться сделать это:

  • Задачи, отправленные управляемому экземпляру ExecutorService, могут продолжать выполняться после завершения жизненного цикла отправляющего компонента. Поэтому компоненты CDI с областью действия @RequestScoped, @SessionScoped или @ConversationScoped не рекомендуется использовать в качестве задач, поскольку нельзя гарантировать, что задачи будут завершены до того, как контекст CDI будет уничтожен.

Вам необходимо собрать данные области запроса и передать их асинхронной задаче при ее создании, независимо от того, используете ли вы утилиты параллелизма или методы @Asynchronous.

person Steve C    schedule 23.12.2015
comment
Спасибо за ответ. В моем случае гарантируется, что задачи будут завершены до того, как область запроса будет уничтожена. Похоже, это ошибка в Wildfly. Я попытаюсь запустить отчет об ошибке. Спасибо за помощь. - person Iaroslav Savytskyi; 26.12.2015
comment
обсуждается поддержка в CDI 2.1. - person Steven; 14.12.2018