我无法理解EJB容器如何使用实例变量管理@Stateless
bean的线程安全性。在解释我的担忧之前,我将举一个简单的例子:
@Stateless
public class BeanTest{
@Inject
private String var;
private Connection connection;
@Resource(name = "jdbc/TestDB")
private DataSource dataSource;
public void modify() {
var = "TestName";
}
@PostConstruct
public void initialize() {
try {
connection = dataSource.getConnection();
} catch (SQLException sqle) {
sqle.printStackTrace();
}
}
@PreDestroy
public void cleanup() {
try {
connection.close();
connection = null;
} catch (SQLException sqle) {
sqle.printStackTrace();
}
}
}
这是我的问题,假设我们的容器支持池:
1。 Pooling vs Thread-safe:
用户1使用BeanTest
的实例并使用modify方法修改了var
,然后他完成了,容器将BeanTest
的实例放入托管池中。当用户2尝试将同一个bean用于请求时,他可能获得由用户1初步修改的BeanTest
的相同实例(我知道也可能获得另一个实例)。那么他会找到实例变量var
的哪个状态(默认值为null
或"TestName"
)?如果它是新修改的那个,这是否意味着即使@Stateless
bean不是100%线程安全的?所以finnaly没有关于线程安全性的容器添加值,因为不使用实例变量使得bean线程安全,即使它不是@Stateless
bean
2。合并vs @PreDestroy
如果bean被返回到托管池而没有被销毁,那么这是否意味着不会调用@Predestroy
方法,在这种情况下连接将保持打开状态?那么,如果我们在池中有30个inft,我们可能有30个未使用的开放连接,这不是性能问题吗?或者这不是@Predestroy
如何与汇集相结合? (使用Connection
只是一个示例,我们可能需要在@Predestroy
中关闭其他类型的资源)
NB: 这不是一个真实的例子,所以我不是在寻找替代解决方案,我关心的是理解整个概念以及如何在应用程序中管理事物服务器,幕后发生的事情
答案 0 :(得分:2)
1)容器保证线程安全,这意味着单个线程一次可以访问给定的SLSB。它与保证状态不会改变无关。 BTW在SLSB中具有可变状态毫无意义。
2)您不希望在SLSB的生命周期内保持连接,因为您有效地阻止它返回到池中而冒疲惫。
答案 1 :(得分:1)
AnotherBean
是无状态的,那么调用AnotherBean.setName()
是没有意义的。如果它是有状态的,那么将一个有状态的bean注入一个无状态的bean是没有意义的(检查是为什么有状态的bean)。关于线程安全:容器不能使你的类线程安全,但它保证单个客户端线程一次使用某个EJB实例(检查Chris的回答引用)。因此,如果您不在EJB客户端的不同线程中使用EJB,那么使用thread confinment 代码是线程安全的。@Stateful
注释不一致。因此,删除connection
状态变量。无论如何,你不想只为你的bean保持一个开放的连接:每次从数据源获取它。另外,在使用它之后不要忘记关闭连接(在try / finally子句中)。使用池时,它的工作方式类似于JDBC连接池:当池/ EJB容器决定它不再需要实例时(例如,当它想要减少实例数或者抛出非application exception时),那么将调用@PreDestroy
方法。