为啥要池化无状态会话 bean?
Posted
技术标签:
【中文标题】为啥要池化无状态会话 bean?【英文标题】:Why pool Stateless session beans?为什么要池化无状态会话 bean? 【发布时间】:2010-09-13 04:24:02 【问题描述】:Java 中的无状态 bean 不会在来自客户端的两次调用之间保持其状态。所以简而言之,我们可以将它们视为具有业务方法的对象。每个方法都接受参数并返回结果。当调用该方法时,正在执行堆栈中创建一些局部变量。当方法返回时,局部变量会从堆栈中删除,如果分配了一些临时对象,它们无论如何都会被垃圾回收。
从我的角度来看,这与通过单独的线程调用同一单个实例的方法没有什么不同。那么为什么容器不能使用一个 bean 的实例而不是池化多个实例呢?
【问题讨论】:
【参考方案1】:池有几件事情。
第一,通过每个实例有一个 bean,您可以保证线程安全(例如,Servlet 不是线程安全的)。
第二,您可以减少 bean 可能具有的任何潜在启动时间。虽然会话 Bean 是“无状态的”,但它们只需要对客户端是无状态的。例如,在 EJB 中,您可以将多个服务器资源注入到一个会话 Bean 中。该状态对于 bean 来说是私有的,但是没有理由不能阻止它从调用到调用。因此,通过池化 bean,您可以将这些查找减少到仅在创建 bean 时发生。
三,你可以使用 bean pool 来限制流量。如果池中只有 10 个 Bean,则最多只能同时处理 10 个请求,其余的将排队。
【讨论】:
“一个,通过每个实例有一个 bean,您可以保证线程安全(例如,Servlet 不是线程安全的)。”线程安全对无状态会话 bean 有何帮助? 当您断言 Servlet 不是线程安全的时,我不明白您的意思。 IIRC,Tomcat 管理控制台也允许我汇集 Servlet。 无状态会话 Bean 是简单的组件。它们可以有“状态”,但状态与组件有关,与客户端无关。 bean 有一个完整的生命周期。因此,您可以有一个本地缓存,例如,在 bean 中,而不必担心同步它。 Tomcat 可能会提供一个 Servlet 实例池,但规范并不要求它。你不能假设一个特定的 servlet 实例一次只能被一个请求访问。 可能更清楚地说,开发人员负责编写线程安全的 servlet——将有多个线程同时访问它。无状态会话 bean 不需要写成线程安全的,因为容器已经保证了这一点(不会有多个线程同时执行;而是有多个 bean,池化)。【参考方案2】:池化可提高性能。
处理所有请求/线程的单个实例会导致大量争用和阻塞。
由于您不知道将使用哪个实例(并且多个线程可以同时使用一个实例),因此 bean 必须是线程安全的。
容器可以根据实际活动管理池大小。
【讨论】:
【参考方案3】:Java EE 模型的事务性使用线程上下文来管理事务生命周期。
存在这种简化,因此无需实现任何特定接口即可直接与 UserTransaction 对象交互;当从 InitialContext 检索事务(或注入会话 bean)时,它被绑定到线程局部变量以供重用(例如,如果无状态会话 bean 中的方法调用另一个也使用注入事务的无状态会话 bean。 )
【讨论】:
【参考方案4】:Statelesss session beans 的生命周期是不存在,Passive 和 MethodReady(Passive 或 Inactive)状态。为了优化性能,而不是遍历 bean 从创建状态到方法就绪状态,容器管理活动和方法之间的 bean通过容器回调的被动状态 - ejbActivate() 和 ejbPassivate() 通过管理 bean 池。
sreenut
【讨论】:
【参考方案5】:方法本质上是线程安全的(包括静态方法)。为什么?很简单,因为方法中的每个变量都是在堆栈内存中创建的,即方法中使用的每个变量都是每次调用创建的(它不是共享的)。但是,参数不是堆栈的一部分。
但是,如果一个方法使用了一个不安全的变量,它就是不安全的:
a) 调用静态字段或变量。但是,它在每一种情况下都会发生。
b) 调用它共享的资源。比如EntityManager。
c) 传递一个不安全的参数。
【讨论】:
以上是关于为啥要池化无状态会话 bean?的主要内容,如果未能解决你的问题,请参考以下文章
在条件下在无状态会话 Bean 中注入特定的 EntityManager