使用@EJB 时,每个托管bean 是不是都有自己的@EJB 实例?
Posted
技术标签:
【中文标题】使用@EJB 时,每个托管bean 是不是都有自己的@EJB 实例?【英文标题】:When using @EJB, does each managed bean get its own @EJB instance?使用@EJB 时,每个托管bean 是否都有自己的@EJB 实例? 【发布时间】:2014-10-20 06:47:29 【问题描述】:我正在为一个 Web 项目使用 JSF 2.2,我现在正在实现登录页面。
我有一个login.xhtml
作为视图,还有一个名为UserLoginView
的支持bean。
这个 bean 有一个 EJB
属性 bean private UserService userService
(如图所示 here)。
这是否意味着每个新的UserLoginView
都会获得一个新的UserService
实例?
在生产环境中这样实现可以吗?
【问题讨论】:
【参考方案1】:这是否意味着每个新的 UserLoginView 都会获得一个新的 UserService 实例?
不。给定的UserService
是@Stateless
EJB。 @Stateless
EJB 被池化并作为容器自动生成的可序列化代理注入。其中,当 EJB 发生异常时的堆栈跟踪就是这方面的证据。您会看到支持 bean 方法和 EJB 方法之间的额外层。
@Stateless
EJB 的自动生成代理类大致如下(实际上它更复杂,例如还需要在此处获取、启动和提交数据库事务,具体取决于 EJB 类的 @TransactionAttribute
和/或方法):
public class UserServiceProxy extends UserService implements Serializable
public User find(Long id)
UserService instance = getAnAvailableInstanceFromPool();
User result = instance.find(id);
releaseInstanceToPool(instance);
return result;
public Long save(User user)
UserService instance = getAnAvailableInstanceFromPool();
Long result = instance.save(user);
releaseInstanceToPool(instance);
return result;
// ...
你看到了吗?它只是从 EJB 池中获取一个可用实例,然后将方法调用委托给它,最后将其释放到池中以供将来重用。正是这个代理实例实际上被注入到您的 JSF 托管 bean 中。
顺便说一句,CDI 也以这种方式工作。这就是为什么使用 CDI 可以将更窄范围的 bean 注入到更广泛范围的 bean 中并且仍然让它按预期工作的原因。 JSF 的@ManagedBean
注入了 actual 实例,因此它不能那样工作。如果 JSF 也使用通过FacesContext
实际抓取当前 bean 实例并委托给它的代理,它会起作用。
只有@Stateful
EJB 实际上与客户端的生命周期相关联。如果托管 bean 作为客户端,它确实会获得“它自己的”实例。另见JSF request scoped bean keeps recreating new Stateful session beans on every request?
而@Singleton
EJB 在池中基本上最多有一个实例。所以每个客户端总是会得到相同的实例。
在生产环境中这样实现可以吗?
当然。否则它们就不存在了。
【讨论】:
感谢您展示代理类的内部工作原理(对于 Java 开发来说也是非常新的,这些看起来都非常有用):)以上是关于使用@EJB 时,每个托管bean 是不是都有自己的@EJB 实例?的主要内容,如果未能解决你的问题,请参考以下文章
sessionscoped 托管 bean 与有状态 ejb
结合 JPA、EJB 和 JSF 托管 bean 的首选设计模式是啥?
将 JSF2 托管 pojo bean 传递到 EJB 或将所需内容放入传输对象