Guice выбрасывает OutOfScopeException при выполнении CompletableFuture

Из потока темы запроса, CompletableFuture s должны быть выполнены задачей, выполняемой в исполнителе. Поставщик предоставляет услугу для конкретного домена MessageService которая является сессионной областью. Эта услуга вводится Guice.

public class MessageProcessingPage {
    private MessageService messageService;

    @Inject
    public MessagProcessingPage (MessageService messageService) {
        this.messageService = messageService;
    }

    // Called by request scoped thread.
    public void onProcessMessagesButton () {
        ExecutorService executorService = Executors.newFixedThreadPool(3);
        CompletableFuture.supplyAsync(
        // Called from a thread from the threadpool.
        () -> {return messageService.retrieveMessageMetadataSet(x, y);}
        , executorService);

        ...

    }

    ...
}

MessageService имеет (объем сессии) MessageRestClient который вводится.

@SessionScoped
public class MessageService {
    private MessageRestClient messageRestClient;

    @Inject
    public MessageRestClient (MessageRestClient messageRestClient) {
        this.messageRestClient = messageRestClient;
    }

    public MessageMetaDataSet retrieveMessageMetadataSet(x, y) {
        List<MessageMetaData> listOfMetaData = messageRestClient.retrieve(x, y, z);
        ...
    }

    ...
}

@SessionScoped
public class MessageRestClient {
    ...
}

Guice попадает в беду, когда он пытается ввести MessageRestClient,

java.util.concurrent.CompletionException: com.google.inject.ProvisionException: Unable to provision, see the following errors:

1) Error in custom provider, com.google.inject.OutOfScopeException: Cannot access scoped [MessageRestClient]. Either we are not currently inside an HTTP Servlet request, or you may have forgotten to apply com.google.inject.servlet.GuiceFilter as a servlet filter for this request.

Я читал о методе в ServletScopes: public static <T> Callable<T> transferRequest(Callable<T> callable) Но я не вижу способа использовать это, так как нет Callables, чтобы играть. Можете ли вы помочь мне с решением?

2 ответа

Решение

При обработке запроса сервлета в Guice, GuiceFilter позаботился об установлении правильного контекста (через ThreadLocal), чтобы он мог знать, в каком запросе вы находитесь, и, следовательно, правильно применять области действия. Экземпляры классов отмечены SessionScope фактически являются прокси-серверами, которые могут получить доступ к этой информации запроса и сеанса из Guice и действовать соответственно.

Задание, которое вы отправили на CompletableFuture работает в отдельном потоке из Guice контроль. Здесь нет ThreadLocal доступно где Guice может получить эту информацию от, и, следовательно, нет Request ни Session информация, что значит, нет [SessionScope, Поскольку прокси не может ничего знать о сеансе, он выдает ошибку, которую вы получаете.

Метод ServletScopes.transferRequest должен внедрить необходимую информацию, чтобы области работали. Должен работать так (но никогда не пытался):

   Callable<MessageMetaDataSet> c = ServletScopes.transferRequest(
               () -> messageService.retrieveMessageMetadataSet(x, y));

   CompletableFuture.supplyAsync(
    () -> c.call()
    , executorService);

Попробуйте это пораньше: Guice @Inject отлично работает:



    import java.util.concurrent.CompletableFuture;

    public class AsyncFire {

        public static > void execAsync(Class asyncClass) {
            T asyncInstance = AsyncInjector.getInjector().getInstance(asyncClass); //magic
            CompletableFuture completableFuture = CompletableFuture.supplyAsync(asyncInstance); //business logic
            completableFuture.exceptionally(asyncInstance); //if error
            completableFuture.thenAccept(asyncInstance); //if success
        }

    }



    public class ExampleAsync extends Async {

        @Inject //it works
        private EntityManager entityManager;

        @Inject //it works
        private DAO dao; //your

    }



    import java.util.function.Consumer;
    import java.util.function.Function;
    import java.util.function.Supplier;

    public abstract class Async implements Supplier, Consumer, Function {
        //...
    }



    import com.google.inject.Guice;
    import com.google.inject.Injector;
    import com.google.inject.persist.PersistService;

    public final class AsyncInjector {

        private static Injector injector = null; 

        public static Injector getInjector() {
            if (injector == null) {
                synchronized (AsyncInjector.class) {
                    if (injector == null) {
                        injector = Guice.createInjector(new MyGuiceModule()); //your guice module
                        PersistService service = injector.getInstance(PersistService.class);
                        service.start();
                    }
                }
            }
            return injector;
        }

    }

Надеюсь, это поможет кому-то!

Другие вопросы по тегам