从请求范围的线程中,CompletableFuture
必须由执行程序中运行的任务完成。提供的供应商使用特定于域的服务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可以参与比赛。你能帮我解决一下吗?
答案 0 :(得分:3)
在Guice
中处理servlet请求时,GuiceFilter
已经负责设置正确的上下文(通过ThreadLocal
),以便它可以知道您在哪个请求中,因此,适当地应用范围。使用SessionScope
注释的类的实例实际上是代理,可以从Guice访问该请求和会话信息并采取相应的行动。
您发送到CompletableFuture
的任务在Guice
控件的单独线程中运行。 ThreadLocal
可以从Guice
获取该信息,因此没有Request
,因此,没有Session
或[SessionScope
信息,这意味着什么,没有 Callable<MessageMetaDataSet> c = ServletScopes.transferRequest(
() -> messageService.retrieveMessageMetadataSet(x, y));
CompletableFuture.supplyAsync(
() -> c.call()
, executorService);
。由于代理无法了解会话的任何信息,因此会引发您遇到的错误。
ServletScopes.transferRequest方法应该注入所需的信息,以便范围有效。应该这样工作(但从未尝试过):
Profile
答案 1 :(得分:0)
尽早尝试: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;
}
}
希望这有助于某人!