【问题标题】:static block is called twice, maybe multiple class loaders?静态块被调用两次,可能是多个类加载器?
【发布时间】:2013-01-04 05:34:56
【问题描述】:

我有一个 MDB EJB,里面有静态块。我使用静态块在应用程序第一次运行时(即部署时)只初始化一些组件一次。 MDB EJB 部署在除 Admin_Server 之外的单独服务器 (My_Server) 上。

问题是静态块被调用了两次!

  • 第一次:在部署 MDB EJB(标记到 My_Server)之后。
  • 第二次:在 JMS 队列(与 MDB 关联的)收到消息之后。

另外,我打印了服务器名称和 pid,两者都是一样的:

System.out.println("server name: " + System.getProperty("weblogic.Name"));
System.out.println("pid: " + ManagementFactory.getRuntimeMXBean().getName().split("@")[0]);

我还注意到一些奇怪的行为。基本上,我附加了一个 Shutdown Hook(从静态块内部)在应用程序关闭时向我发送电子邮件。

  • 我在关闭 My_Server 后收到通知。
  • 我在关闭 Admin_Server 后也会收到通知。

我该如何解决这个问题?


一些额外的信息:

Weblogic version: 10.3.0
EJB version: 3.0

【问题讨论】:

    标签: java jakarta-ee weblogic ejb-3.0 classloader


    【解决方案1】:

    只有当你有多个类加载器时才会发生这种情况。我不会在 EJB 中使用静态初始化程序,而是依赖 EJB 生命周期挂钩或将初始化程序导出到非托管类中。

    EJB 3.1 添加了 @Singleton 和 @Startup 之类的注释,但不幸的是,在 3.0 中,您只能使用基于提供程序的解决方案来保证这些保证。

    管理员与常规服务器行为相当普遍,因为 WebLogic 通常部署到两者。请参阅this page 了解更多信息。

    对于 Weblogic 关闭挂钩,请检查 this documentation page

    【讨论】:

    • +1 感谢您的回答。我需要的是在部署时只做一次初始化。我知道的唯一 EJB 生命周期注释是 @PostConstruct,这是无效的,因为 Weblogic 有时会创建 MDB 的多个实例。 “您使用的是哪个应用服务器”是什么意思?
    【解决方案2】:

    是的,您可以多次执行静态初始化程序的唯一方法是,如果您实际上已经加载了该类的两个不同副本。只有当你有两个不同的类加载器都加载类时,才会发生这种情况。

    防止这种情况的方法是安排有问题的类由两个类加载器的共同祖先类加载器加载。我不知道您将如何使用 Weblogic 来执行此操作,但对于 Tomcat,您会将相关的 JAR 文件放入指定的公共库目录中,该目录由容器中运行的所有 webapps 共享。

    【讨论】:

    • 我们有一个 .jar 文件,它使用系统类加载器加载,然后由 Tomcat 类加载器再次加载。我们从 Tomcat webapp 中删除了 .jar 以解决我们的问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-06-22
    • 2012-01-20
    • 1970-01-01
    • 1970-01-01
    • 2012-05-01
    • 2021-02-11
    • 2016-06-26
    相关资源
    最近更新 更多