"non-managed" 实用程序 class 的并发访问和扩展
Concurrent access and scaling of "non-managed" utility class
如果我有一个有状态 class 需要类似实用程序的无状态 class 来对其执行操作。这些有状态 classes 保存在容器(有状态)class 的列表中。这就是我对普通 Java:
所做的
class Container {
List<Stateful> sfList;
}
class Stateful {
List<String> list;
void someMethod() {
list.add("SF");
Stateless.foo(this);
}
class Stateless {
public static void foo(Stateful sf) {
sf.getList().add("SL");
}
}
在main
里面是这样的过程:
Stateful sf = new Stateful();
sfList.add(sf);
sf.someMethod();
现在使用 JavaEE CDI 我会做:
class StatefulBean {
List<String> list;
@Inject
StatelessBean slsb;
void someMethod() {
list.add("SF");
slsb.add(this);
}
@Stateless
class StatelessBean {
public void add(StatefulBean sfsb) {
sfsb.add("SL");
}
}
在这种情况下,所有 StatefulBean 都可以访问 StatelessBean 的共享池而不会出现并发问题,并且它将根据请求进行适当扩展。
但是,由于 Stateful
不是托管 bean,我无法注入它,所以我改用了实用程序 class。此外,我正在使用构造函数创建 Stateful
,因此我无法将无状态 bean 注入其中(我将使用它获得 NPE)。
我的问题是:
- 无状态注入方法(前提是它可行)和实用程序 class 方法之间是否存在并发性和可扩展性差异?
- 如何使 EE 注入方法起作用?
Are there concurrency and scalabilty differences between the stateless injection approach (provided it would work) and the utility class approach?
是的,主要是围绕管理的损失。在每次调用该方法时实例化 Stateful
的方式不涉及池化。这将导致您创建比您可能需要的更多的实例。
另一个损失是在可伸缩性方面。在容器将管理分布式环境中有状态 bean 的钝化和激活的地方,手动方法将确保您管理自己的激活和钝化。
Since Stateful
is not a managed bean..
不正确。根据 CDI Spec,任何满足所列条件的 java class(在您的情况下,默认的无参数构造函数)都是托管 bean。这意味着您可以 @Inject
StatelessBean
到 Stateless
并且容器将有义务。要允许此级别的管理,您需要在 beans.xml.
中设置 bean-discovery-mode=all
即使使用(显然不必要的)循环引用,正常的 Java 并发规则也适用:只要您正在操作的状态不是静态的或处于静态 class,您重新线程安全。对该静态方法的每个线程调用仍然在单独的堆栈上运行,因此没有问题。
How can I make the EE injection approach work?
If you need on-demand instantiation of Stateless
(or any other bean really), use the CDI Instance
to programmatically obtain a managed instance of any class you want. You can now add something like this to Container
:
@Inject @Dependent Instance<Stateful> stateful;
@PostConstruct
public void createStateless(){
//instantiate sfList;
sfList.add(stateful.get()); //execute as many times as you need
}
如果我有一个有状态 class 需要类似实用程序的无状态 class 来对其执行操作。这些有状态 classes 保存在容器(有状态)class 的列表中。这就是我对普通 Java:
所做的class Container {
List<Stateful> sfList;
}
class Stateful {
List<String> list;
void someMethod() {
list.add("SF");
Stateless.foo(this);
}
class Stateless {
public static void foo(Stateful sf) {
sf.getList().add("SL");
}
}
在main
里面是这样的过程:
Stateful sf = new Stateful();
sfList.add(sf);
sf.someMethod();
现在使用 JavaEE CDI 我会做:
class StatefulBean {
List<String> list;
@Inject
StatelessBean slsb;
void someMethod() {
list.add("SF");
slsb.add(this);
}
@Stateless
class StatelessBean {
public void add(StatefulBean sfsb) {
sfsb.add("SL");
}
}
在这种情况下,所有 StatefulBean 都可以访问 StatelessBean 的共享池而不会出现并发问题,并且它将根据请求进行适当扩展。
但是,由于 Stateful
不是托管 bean,我无法注入它,所以我改用了实用程序 class。此外,我正在使用构造函数创建 Stateful
,因此我无法将无状态 bean 注入其中(我将使用它获得 NPE)。
我的问题是:
- 无状态注入方法(前提是它可行)和实用程序 class 方法之间是否存在并发性和可扩展性差异?
- 如何使 EE 注入方法起作用?
Are there concurrency and scalabilty differences between the stateless injection approach (provided it would work) and the utility class approach?
是的,主要是围绕管理的损失。在每次调用该方法时实例化 Stateful
的方式不涉及池化。这将导致您创建比您可能需要的更多的实例。
另一个损失是在可伸缩性方面。在容器将管理分布式环境中有状态 bean 的钝化和激活的地方,手动方法将确保您管理自己的激活和钝化。
Since
Stateful
is not a managed bean..
不正确。根据 CDI Spec,任何满足所列条件的 java class(在您的情况下,默认的无参数构造函数)都是托管 bean。这意味着您可以 @Inject
StatelessBean
到 Stateless
并且容器将有义务。要允许此级别的管理,您需要在 beans.xml.
bean-discovery-mode=all
即使使用(显然不必要的)循环引用,正常的 Java 并发规则也适用:只要您正在操作的状态不是静态的或处于静态 class,您重新线程安全。对该静态方法的每个线程调用仍然在单独的堆栈上运行,因此没有问题。
How can I make the EE injection approach work? If you need on-demand instantiation of
Stateless
(or any other bean really), use the CDIInstance
to programmatically obtain a managed instance of any class you want. You can now add something like this toContainer
:
@Inject @Dependent Instance<Stateful> stateful;
@PostConstruct
public void createStateless(){
//instantiate sfList;
sfList.add(stateful.get()); //execute as many times as you need
}