[英]RequestScoped with bean re-use
I have a class/bean that manages an object (in this example the EngineManager contains an Engine object).我有一个管理 object 的类/bean(在此示例中,EngineManager 包含一个 Engine 对象)。 The Engine object cannot be used concurrently and its initialization is a bit time consuming.
Engine object 不能同时使用,初始化有点费时。 However it is possible to create multiple instances of the EngineManager and hence multiple Engine instances.
但是,可以创建多个 EngineManager 实例,从而创建多个 Engine 实例。
public class EngineManager
{
private Engine engine;
@PostConstruct
public void init()
{
this.engine = // ... perform costly initialization
}
public void doSomethingWithEngine()
{
// ...
}
}
I'm trying to figure out which CDI scope to use for the class, that manages this object.我试图找出哪个 CDI scope 用于管理这个 object 的 class。
So my question is: Is there a (CDI) way to所以我的问题是:是否有(CDI)方法可以
In short: To my knowledge, there is no way to solve this strictly within CDI without extra effort.简而言之:据我所知,没有额外的努力就无法在 CDI 内严格解决这个问题。 Here are some generic thoughts:
以下是一些一般性的想法:
This problem is similar to that of the DB connection pool.这个问题与DB连接池的问题类似。 One way to solve it is with a pool of
Engine
instances, from which the EngineManager
(s) pick.解决它的一种方法是使用
EngineManager
从中选择的Engine
实例池。
Elaborating a bit, and if you use an engine pool, the EngineManager
can be @ApplicationScoped
, as long as the pool guarantees that each thread gets a different Engine
.详细说明一下,如果您使用引擎池,则
EngineManager
可以是@ApplicationScoped
,只要该池保证每个线程都获得不同的Engine
。
An interesting aspect of this is how do you deal with unavailability of Engine
instances.一个有趣的方面是如何处理
Engine
实例的不可用。 Throwing an exception is the simplest answer, but might not be appropriate for you use case.抛出异常是最简单的答案,但可能不适合您的用例。 Blocking the current thread (probably with a timeout) until an
Engine
is available is another sub-optimal solution because it will not scale well under traffic.在
Engine
可用之前阻塞当前线程(可能有超时)是另一个次优解决方案,因为它在流量下无法很好地扩展。
If your environment allows, you may want to consider an asynchronous solution, in combination with the pool.如果您的环境允许,您可能需要考虑结合池的异步解决方案。 An
ExecutorService
(see ManagedExecutorService
in JEE environments) where you submit tasks;您提交任务的
ExecutorService
(请参阅 JEE 环境中的ManagedExecutorService
); JMS or other queuing mechanism might be more complex to setup (again depending on your environment) but can offer reliability in the form of message persistence (if the server crashes after you submit your work but before retrieving the result, it can resume and complete the work when it comes back online). JMS 或其他排队机制的设置可能更复杂(同样取决于您的环境),但可以以消息持久性的形式提供可靠性(如果服务器在您提交工作后但在检索结果之前崩溃,它可以恢复并完成当它重新联机时工作)。 Going full async requires more effort, but might be more appropriate if your specific use case justifies it.
完全异步需要更多努力,但如果您的特定用例证明它是合理的,则可能更合适。
Reactions to the comments:对评论的反应:
Nikos answer is good , so this one is just to expand it a bit. Nikos 的回答很好,所以这个只是为了扩大一点。 There is indeed no ready-to-use solution for this problem.
对于这个问题,确实没有现成的解决方案。 From what I understood, the main issue here is the
Engine
object and it's sharing.据我了解,这里的主要问题是
Engine
object 和它的共享。 You want to be able to hold n
instances and distribute them between m
EngineManager
instances.您希望能够持有
n
实例并在m
个EngineManager
实例之间分配它们。
Note that if you use @Inject
to get Engine
to EngineManager
the engine is bound to the manager for the lifecycle of the manager.请注意,如果您使用
@Inject
将Engine
获取到EngineManager
,则引擎在管理器的生命周期内绑定到管理器。 So if you want to swap it dynamically (eg one manager using different engines for different invocations), then you would have to also use dynamic resolution ( Instance<T>
).因此,如果您想动态交换它(例如,一个管理器使用不同的引擎进行不同的调用),那么您还必须使用动态解析(
Instance<T>
)。 Based on this your EngineManager
can be either dependent or application scoped.基于此,您的
EngineManager
可以是依赖的或应用程序范围的。
I can think of two ways to go about the Engine
instance being shares and having multiple instances.我可以想到两种方法来 go 关于
Engine
实例是共享并具有多个实例。
Create a bean that holds a @Dependent
scope producer for Engine
.为
Engine
创建一个包含@Dependent
scope 生产者的 bean。 Now this producer gets called for every injection of Engine
and you can control what it returns.现在,每次注入
Engine
都会调用这个生产者,您可以控制它返回的内容。 The bean can hold a collection of Engines and sometimes it gives you an existing one if they are free, sometimes it could create new one. bean 可以包含一组引擎,有时如果它们是免费的,它会为您提供现有的引擎,有时它可以创建新的引擎。 Thread safety is up to you though!
不过,线程安全取决于您!
Define your own custom scope that will fit your needs.定义您自己的定制 scope 以满足您的需求。 This requires some expertise and usage of Quarkus specific APIs as in CDI you would normally use extensions but you cannot do that in Quarkus.
这需要一些专业知识和Quarkus 特定 API的使用,因为在 CDI 中您通常会使用扩展,但在 Quarkus 中不能这样做。 For instance in Weld SE, you have
@ThreadScoped
which might be something that you could re-implement as custom scope in Quarkus and use in case you want an Engine
to be on a per-thread basis.例如,在Weld SE 中,您有
@ThreadScoped
,您可以在 Quarkus 中将其重新实现为自定义 scope 并在您希望Engine
基于每个线程时使用。 However, custom scoped can really do next to anything, this is just an example.然而,自定义范围真的可以做任何事情,这只是一个例子。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.