【发布时间】:2010-12-21 10:22:54
【问题描述】:
在传统的 n 层 web 应用程序中,servlet 用于 web 层,ejbs(2.0) 用于 biz 层,使 servlet 模型多线程和 ejb 模型单线程背后的基本原理是什么?
即所有请求只有 1 个 servlet 实例,但对于 ejbs,对于每个请求,都有一个从 bean 池分配的新 bean 实例。
【问题讨论】:
在传统的 n 层 web 应用程序中,servlet 用于 web 层,ejbs(2.0) 用于 biz 层,使 servlet 模型多线程和 ejb 模型单线程背后的基本原理是什么?
即所有请求只有 1 个 servlet 实例,但对于 ejbs,对于每个请求,都有一个从 bean 池分配的新 bean 实例。
【问题讨论】:
对于特定的Servlet,确实只有一个实例,因为它们应该是无状态的。在实践中,情况并非总是如此,但就这样吧。
但是,Stateless session beans (SLSB) 有多个实例,并且这些实例是池化的。
根据他们的定义,stateless session beans 是无状态的,所以从表面上看,这似乎是一个悖论。问题是,虽然stateless session beans 在对他们进行的个人调用方面是无状态的,但实际上它们经常有状态。
这种状态的形式是对其他资源的引用。 JPA entity manager,不是线程安全的,是这里的一个典型例子。在对stateless session bean 的单次调用期间,调用者必须拥有对该资源的独占访问权。当调用返回时,下一个调用者可以拥有独占访问权限等。
如果使用单个实例,那么要么所有调用者都必须相互等待(这当然是为了提高性能),要么他们将同时访问这个单个实例。在后一种情况下,bean 实现者必须手动锁定非线程安全资源,例如 entity manager,这通常很脆弱,容易出错,最终仍然会导致调用者相互等待。
所以,为了提高性能,仍然有安全保障,使用了多个实例。
然后这些实例会被池化并重新使用,而不是为每个请求重新创建,因为查找、初始化和注入 bean 的所有必需依赖项可能很耗时。
所有这些因此也自动意味着如果您将实体管理器或其他非线程安全资源注入 Servlet(这是允许的),您可能会遇到问题。这是 Java EE 架构中的一个小漏洞,当然可以通过简单地使用无状态会话 bean 轻松解决。
【讨论】:
我认为通常 servlet 对 EJB 中实现的繁重逻辑呈现出薄薄的外观。 Servlet 应该是无状态的,因此没有理由为同一个 Servlet 创建多个实例。
如果您只使用无状态 bean,我认为没有理由也有多个实例。但是有状态的 EJB 具有状态,因此您需要每个同时请求的实例。
我希望我没有说废话。
【讨论】: