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;
}
}
Надеюсь, это поможет кому-то!