Java应用服务器中的单例。。这主意有多糟糕?

Java应用服务器中的单例。。这主意有多糟糕?,java,jakarta-ee,jboss,glassfish,ejb-3.0,Java,Jakarta Ee,Jboss,Glassfish,Ejb 3.0,我目前正在编写一些旧的java代码,这些代码是在没有考虑应用服务器的情况下开发的。它基本上是一堆带有输入接口和输出接口的“黑匣子代码”。“黑匣子”类中的所有内容都是包含状态的静态数据结构,这些状态以一定的时间间隔(每10秒)执行算法。黑盒是从主方法开始的 为了让这对我自己来说容易些,我想把“黑匣子”变成一个单身汉。基本上,任何想要访问黑盒子内部逻辑的人都会得到相同的实例。这将允许我使用消息驱动bean作为黑盒的输入,使用某种JMS发布器作为黑盒的输出 这主意有多糟糕?有什么建议吗 不过,我最担心

我目前正在编写一些旧的java代码,这些代码是在没有考虑应用服务器的情况下开发的。它基本上是一堆带有输入接口和输出接口的“黑匣子代码”。“黑匣子”类中的所有内容都是包含状态的静态数据结构,这些状态以一定的时间间隔(每10秒)执行算法。黑盒是从主方法开始的

为了让这对我自己来说容易些,我想把“黑匣子”变成一个单身汉。基本上,任何想要访问黑盒子内部逻辑的人都会得到相同的实例。这将允许我使用消息驱动bean作为黑盒的输入,使用某种JMS发布器作为黑盒的输出

这主意有多糟糕?有什么建议吗

不过,我最担心的一个问题是,“黑匣子”代码中可能存在我不知道的线程

EJB中是否有“应用程序范围的对象”之类的东西


注意:我使用Glassfish远非一个坏主意,实际上在我看来它可能是一个相当不错的主意


仅仅从程序设计的角度来看:如果你的黑匣子在概念上是一个“对象”,它的属性和方法对它们起作用,那么就把它变成一个对象,即使只有其中一个被实例化。

我想说,创建一个单例实际上是唯一可行的想法。假设已知此“黑盒”中的代码使用静态字段,则创建此外观的两个实例是绝对不安全的。否则结果是不可预测的。

它应该会起作用,但您可能需要处理一些问题

线程,正如您所提到的。MDB在EJB容器中运行,您无法在其中创建自己的线程,因此您可能会遇到一个潜在的问题。如果您可以访问实际代码(听起来像是这样),那么您可能需要进行一些重构,以消除线程或使用“批准的”线程方法。CommonJ TimerManager可能会在您所述的情况下工作,因为它在一个时间间隔内执行某些任务。大多数应用服务器都有可用的实现(WAS和Weblogic都包含了它)


类加载-这取决于您的配置。如果单例是在同一个EAR中从MDB创建和操作的,那么您就可以了。单独的EAR将意味着不同的类装入器和您的多个Singleton实例。没有更多信息,无法评论这是否是您的问题。

如果您使用简单的Singleton,一旦进入群集环境,您将面临问题。

在这种情况下,您在多个JVM上有多个类加载器,您的sinlgeton模式中断,因为您将有多个该类的实例

在应用服务器(可能在集群环境中)中,单例的唯一可接受的用途是当您认为单例完全没有状态,并且仅用于方便访问全局数据/函数时

我建议检查您的应用程序服务器供应商针对此问题的解决方案。大多数(如果不是所有供应商的话)都会为您的需求提供一些解决方案


特别是玻璃鱼,你说你正在使用,看看。这可能很简单,只需添加一个注释。

修复代码以尽快消除静态。单身汉并不是朝着正确的方向迈出的一步——他们只是增加了额外的误导。

我遗漏了一点?您提到“黑盒代码”包含状态。MDB可能被限制为每个目的地只有一个实例,但如果没有适当的配置,您最终会得到几个MDB。所有这些都与您的单个“黑盒代码”实例一起工作。对我来说,这似乎不是一个好主意,因为一个bean将覆盖另一个bean之前创建的“黑盒代码”状态。

不要在状态可能更改的地方使用单例


公开黑盒类的全局实例似乎不是一种可行的方法。通常情况下,单例看起来会让事情变得更容易,而且是以一种他们可以做到的方式,但它经常会反过来咬你,你最终不得不重新构造一大块代码。

在Web服务器世界中,对象的作用域可以是请求、会话或应用程序。也许您需要的是一个应用程序范围对象


在文档中搜索“应用程序范围对象”或“应用程序生命周期对象”。

在我看来,更适合您需求的工件是JBoss MBean。(如果您考虑将JBoss作为候选者)

在JBoss集群的情况下,MBean也可以作为单例部署

我希望这对你有用


拉法.< /p> < p>为什么不为空白框创建一个REST接口,让客户机进行HTTP调用?

IMO,有一个EJB容器是您的单体需要的好主意。在JavaEE6中,在会话bean中放置@Singleton注释可以得到一个命名的Singleton。

这是最重要的考虑因素。由于您的应用程序运行在应用程序服务器上,因此会自动假设您可以向其抛出另一台服务器。如果你不在那里说“不要那样做”,他们会诅咒你好几代人。对“其他EJB容器”有什么建议吗?更新了我的回答,这取决于你实际使用的应用服务器。不管是否有多个MDB实例,他们都会访问同一个“黑盒”实例,如果严格执行单例模型。