Guice 在执行 CompletableFuture 时抛出 OutOfScopeException
Guice throwing OutOfScopeException when executing 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 参与进来。你能帮我解决一下吗?
在 Guice
中处理 servlet 请求时,GuiceFilter
已负责设置正确的上下文(通过 ThreadLocal
),以便它可以知道您在哪个请求中因此,正确应用范围。用 SessionScope
注释的 类 的实例实际上是 代理 可以从 Guice 访问该请求和会话信息并采取相应的行动。
您发送给 CompletableFuture
的任务在不受 Guice
控制的单独线程中运行。 Guice
可以从中获取该信息的地方没有 ThreadLocal
,因此,没有 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); <b>//magic</b>
CompletableFuture completableFuture = CompletableFuture.supplyAsync(asyncInstance); //business logic
completableFuture.exceptionally(asyncInstance); //if error
completableFuture.thenAccept(asyncInstance); //if success
}
}
public class ExampleAsync extends Async {
@Inject <b>//it works</b>
private EntityManager entityManager;
@Inject <b>//it works</b>
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()); <b>//your guice module</b>
PersistService service = injector.getInstance(PersistService.class);
service.start();
}
}
}
return injector;
}
}
希望这对某人有所帮助!
在请求范围的线程中,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 参与进来。你能帮我解决一下吗?
在 Guice
中处理 servlet 请求时,GuiceFilter
已负责设置正确的上下文(通过 ThreadLocal
),以便它可以知道您在哪个请求中因此,正确应用范围。用 SessionScope
注释的 类 的实例实际上是 代理 可以从 Guice 访问该请求和会话信息并采取相应的行动。
您发送给 CompletableFuture
的任务在不受 Guice
控制的单独线程中运行。 Guice
可以从中获取该信息的地方没有 ThreadLocal
,因此,没有 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); <b>//magic</b>
CompletableFuture completableFuture = CompletableFuture.supplyAsync(asyncInstance); //business logic
completableFuture.exceptionally(asyncInstance); //if error
completableFuture.thenAccept(asyncInstance); //if success
}
}
public class ExampleAsync extends Async {
@Inject <b>//it works</b>
private EntityManager entityManager;
@Inject <b>//it works</b>
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()); <b>//your guice module</b>
PersistService service = injector.getInstance(PersistService.class);
service.start();
}
}
}
return injector;
}
}
希望这对某人有所帮助!