正确使用 Servlet 中的 Stateful Bean

2024-04-20

目前,我们有一个注入到 Servlet 中的 Stateful bean。问题是有时我们会得到一个Caused by: javax.ejb.ConcurrentAccessException: SessionBean is executing another request. [session-key: 7d90c02200a81f-752fe1cd-1]在有状态 bean 上执行方法时。

public class NewServlet extends HttpServlet {  
    @EJB  
    private ReportLocal reportBean;

    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();
        try {
           String[] parameters  = fetchParameters(request);
           out.write(reportBean.constructReport(parameters));
        } finally { 
            out.close();
        }
    } 
}

在上面的代码中,constructReport将检查是否需要打开与报告中指定的数据库的新连接,然后根据指定参数构建的查询构建 HTML 格式的报告。

我们选择使用有状态 Bean 而不是无状态 Bean 的原因是因为我们需要打开到未知数据库的数据库连接并对其执行查询。对于无状态 bean,重复打开和关闭与每个注入的 bean 实例的数据库连接似乎效率极低。


有关的更多详细信息并发访问异常 http://docs.oracle.com/javaee/6/api/javax/ejb/ConcurrentAccessException.html:根据 EJB 规范,对 SLSB 的访问由应用程序同步。服务器。然而,SFS​​B 的情况并非如此。确保 SFSB 不会被同时访问的重担落在了应用程序开发人员的肩上。

为什么?那么,SLSB 的同步仅在实例级别是必要的。也就是说,SLSB 的每个特定实例都是同步的,但您可能在池中或集群中的不同节点上有多个实例,并且不同实例上的并发请求不是问题。遗憾的是,由于实例的钝化/激活以及跨集群的复制,这对于 SFSB 来说并不那么容易。这就是为什么规范不强制执行这一点。看一下这次讨论 https://jira.jboss.org/jira/browse/JBAS-1443如果您对该主题感兴趣。

这意味着从 servlet 使用 SFSB 很复杂。用户在同一会话中拥有多个窗口,或者在渲染完成之前重新加载页面可能会导致并发访问。理论上,在 servlet 中完成的对 EJB 的每次访问都需要在 bean 本身上进行同步。我所做的是创建一个调用处理程序 http://docs.oracle.com/javase/6/docs/api/java/lang/reflect/InvocationHandler.html同步特定 EJB 实例上的所有调用:

public class SynchronizationHandler implements InvocationHandler {

 private Object target;  // the EJB

 public SynchronizationHandler( Object bean )
 {
        target = bean;
 }

  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
  {
    synchronized( target )
    {
       // invoke method to the target EJB
    }
  }

}

然后,在获得对 EJB 的远程引用后,立即用SynchronizationHandler。这样,您就可以确保您的应用程序不会同时访问该特定实例(只要它仅在一个 JVM 中运行)。您还可以编写一个常规包装类来同步 bean 的所有方法。

尽管如此,我的结论是:尽可能使用 SLSB。

EDIT:

这个答案反映了 EJB 3.0 规范(第 4.3.13 节):

不允许客户端对有状态会话进行并发调用 目的。如果客户端调用的业务方法正在进行 例如,当另一个客户端调用来自相同或不同的调用时 客户端,到达有状态会话 Bean 类的同一个实例, 如果第二个客户端是 bean 业务接口的客户端,则 并发调用可能会导致第二个客户端接收到 javax.ejb.ConcurrentAccessException

EJB 3.1(第 4.3.13 节)中删除了此类限制:

默认情况下,允许客户端并发调用有状态的 会话对象和容器需要序列化这样的 并发请求。

[...]

Bean 开发人员可以选择指定并发客户端 禁止向有状态会话 bean 发出请求。这是使用完成的 @AccessTimeout 注释或访问超时部署描述符 值为0的元素。此时,如果客户端调用的业务 当另一个客户端调用时,方法正在实例上进行, 来自相同或不同的客户端,到达同一实例 有状态会话 Bean,如果第二个客户端是该 Bean 的客户端 业务接口或无接口视图、并发调用 必须导致第二个客户端收到 javax.ejb.ConcurrentAccessException

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

正确使用 Servlet 中的 Stateful Bean 的相关文章

  • 如何为最终用户方便地启动Java GUI程序

    用户想要从以下位置启动 Java GUI 应用程序Windows 以及一些额外的 JVM 参数 例如 javaw Djava util logging config file logging properties jar MyGUI jar
  • Java Swing:从 JOptionPane 获取文本值

    我想创建一个用于 POS 系统的新窗口 用户输入的是客户拥有的金额 并且窗口必须显示兑换金额 我是新来的JOptionPane功能 我一直在使用JAVAFX并且它是不同的 这是我的代码 public static void main Str
  • 如何使用 Java 和 Selenium WebDriver 在 C 目录中创建文件夹并需要将屏幕截图保存在该目录中?

    目前正在与硒网络驱动程序和代码Java 我有一种情况 我需要在 C 目录中创建一个文件夹 并在该文件夹中创建我通过 selenium Web 驱动程序代码拍摄的屏幕截图 它需要存储在带有时间戳的文件夹中 如果我每天按计划运行脚本 所有屏幕截
  • 如何默认将 Maven 插件附加到阶段?

    我有一个 Maven 插件应该在编译阶段运行 所以在项目中consumes我的插件 我必须做这样的事情
  • Java EE:如何获取我的应用程序的 URL?

    在 Java EE 中 如何动态检索应用程序的完整 URL 例如 如果 URL 是 localhost 8080 myapplication 我想要一个可以简单地将其作为字符串或其他形式返回给我的方法 我正在运行 GlassFish 作为应
  • 制作一个交互式Windows服务

    我希望我的 Java 应用程序成为交互式 Windows 服务 用户登录时具有 GUI 的 Windows 服务 我搜索了这个 我发现这样做的方法是有两个程序 第一个是服务 第二个是 GUI 程序并使它们进行通信 服务将从 GUI 程序获取
  • Final字段的线程安全

    假设我有一个 JavaBeanUser这是从另一个线程更新的 如下所示 public class A private final User user public A User user this user user public void
  • Android MediaExtractor seek() 对 MP3 音频文件的准确性

    我在使用 Android 时无法在eek 上获得合理的准确度MediaExtractor 对于某些文件 例如this one http www archive org download emma solo librivox emma 01
  • Spark 1.3.1 上的 Apache Phoenix(4.3.1 和 4.4.0-HBase-0.98)ClassNotFoundException

    我正在尝试通过 Spark 连接到 Phoenix 并且在通过 JDBC 驱动程序打开连接时不断收到以下异常 为简洁起见 下面是完整的堆栈跟踪 Caused by java lang ClassNotFoundException org a
  • 控制Android的前置LED灯

    我试图在用户按下某个按钮时在前面的 LED 上实现 1 秒红色闪烁 但我很难找到有关如何访问和使用前置 LED 的文档 教程甚至代码示例 我的意思是位于 自拍 相机和触摸屏附近的 LED 我已经看到了使用手电筒和相机类 已弃用 的示例 但我
  • 列出jshell中所有活动的方法

    是否有任何命令可以打印当前 jshell 会话中所有新创建的方法 类似的东西 list但仅适用于方法 您正在寻找命令 methods all 它会打印所有方法 包括启动 JShell 时添加的方法 以及失败 被覆盖或删除的方法 对于您声明的
  • Spring @RequestMapping 带有可选参数

    我的控制器在请求映射中存在可选参数的问题 请查看下面的控制器 GetMapping produces MediaType APPLICATION JSON VALUE public ResponseEntity
  • 如何在PreferenceActivity中添加工具栏

    我已经使用首选项创建了应用程序设置 但我注意到 我的 PreferenceActivity 中没有工具栏 如何将工具栏添加到我的 PreferenceActivity 中 My code 我的 pref xml
  • getResourceAsStream() 可以找到 jar 文件之外的文件吗?

    我正在开发一个应用程序 该应用程序使用一个加载配置文件的库 InputStream in getClass getResourceAsStream resource 然后我的应用程序打包在一个 jar文件 如果resource是在里面 ja
  • 如何从泛型类调用静态方法?

    我有一个包含静态创建方法的类 public class TestClass public static
  • 获取 JVM 上所有引导类的列表?

    有一种方法叫做findBootstrapClass对于一个类加载器 如果它是引导的 则返回一个类 有没有办法找到类已经加载了 您可以尝试首先通过例如获取引导类加载器呼叫 ClassLoader bootstrapLoader ClassLo
  • 捕获的图像分辨率太大

    我在做什么 我允许用户捕获图像 将其存储到 SD 卡中并上传到服务器 但捕获图像的分辨率为宽度 4608 像素和高度 2592 像素 现在我想要什么 如何在不影响质量的情况下获得小分辨率图像 例如我可以获取或设置捕获的图像分辨率为原始图像分
  • 使用 JMF 创建 RTP 流时出现问题

    我正处于一个项目的早期阶段 需要使用 RTP 广播DataStream创建自MediaLocation 我正在遵循一些示例代码 该代码目前在rptManager initalize localAddress 出现错误 无法打开本地数据端口
  • 按日期对 RecyclerView 进行排序

    我正在尝试按日期对 RecyclerView 进行排序 但我尝试了太多的事情 我不知道现在该尝试什么 问题就出在这条线上适配器 notifyDataSetChanged 因为如果我不放 不会显示错误 但也不会更新 recyclerview
  • Spring Boot @ConfigurationProperties 不从环境中检索属性

    我正在使用 Spring Boot 1 2 1 并尝试创建一个 ConfigurationProperties带有验证的bean 如下所示 package com sampleapp import java net URL import j

随机推荐