代码之家  ›  专栏  ›  技术社区  ›  Matt Ball

如何编写JavaEE/EJB SuntLon?

  •  7
  • Matt Ball  · 技术社区  · 15 年前

    一天前,我的应用程序是一个EAR,包含一个WAR、一个EJB JAR和两个实用JAR文件。我在其中一个实用程序文件中有一个pojo singleton类,它起作用了,而且与世界上的一切都很好:

    EAR
     |--- WAR
     |--- EJB JAR
     |--- Util 1 JAR
     |--- Util 2 JAR
     |--- etc.
    

    然后我创建了第二场战争,发现(困难的方式)每一场战争都有自己的类加载器,所以每一场战争都会看到一个不同的单件,事情就从那里开始了。这不是很好。

    EAR
     |--- WAR 1
     |--- WAR 2
     |--- EJB JAR
     |--- Util 1 JAR
     |--- Util 2 JAR
     |--- etc.
    

    所以,我正在寻找一种方法来创建一个JavaSuntLon对象,它可以跨战争(跨类加载程序)工作?. The @Singleton 在我发现JBoss5.1似乎不支持这个注释(它是作为EJB3.1的一部分添加的)之前,EJB注释看起来很有前途。我错过什么了吗-我能用吗 @ Singleton 使用JBoss 5.1?现在升级到jboss as 6不是一个选项。

    另外,我也很高兴不用EJB来实现我的单例。我还能做些什么来解决这个问题?基本上,我需要一个半应用程序范围的*钩子钩住一大堆其他对象,比如各种缓存数据和应用程序配置信息。作为最后的手段,我已经考虑将我的两次战争合并为一次,但那将是相当地狱般的。

    *意思:基本上可以在某一层以上的任何地方使用;现在,主要是在我的战争中——视图和控制器(松散的意义上)。

    编辑: 我真的应该打电话给它 Java EE 不是J2EE,不是吗?


    编辑2: 再次感谢@yishai的帮助。经过一些尝试和错误之后,我似乎已经了解了如何在JBoss5下的战争中使用一个类加载器。为了我自己的利益,我将在下面详细介绍这一点,希望其他人也能发现这一点。

    注意,这与在JBoss4下做这件事有很大的不同(参见下面的Yishai的答案或我的链接)。

    而不是写 jboss-web.xml 对于每一场战争, jboss.xml 对于EAR EJB-JAR,将 jboss-classloading.xml 每个战争中的文件,与DD在同一位置( web.xml )内容 jboss-classloading.xml文件 应该是:

    <?xml version="1.0" encoding="UTF-8"?>
    <classloading
        xmlns="urn:jboss:classloading:1.0"
        name="mywar.war"
        domain="DefaultDomain"
        parent-domain="Ignored"
        export-all="NON_EMPTY"
        import-all="true">
    </classloading>
    

    这源于JBoss CW here ,而(我认为)对jboss 4.x的作用是描述的 here . 有关jboss类加载(ing/ers)的更多常规信息:

    据我所知,与JBoss4相比,JBoss5缺少JBossCommunitywiki文档。

    5 回复  |  直到 12 年前
        1
  •  11
  •   Community CDub    8 年前

    虽然ejb3.1规范引入了singleton,而您的jboss版本不支持它,但是您可以使用jboss@service注释创建singleton。指令 here . 而且,似乎您已经配置了JBoss来将EJB jar和war彼此隔离开来。你不必这么做。你可以看看 loader-repository 标记jboss特定的XML文件,以便整个EAR共享一个类加载器(或者至少两次战争共享一个类加载器)。

    尽管如此,我同意@duffymo的观点,即在两次战争之间共享状态的一个单件是一个想法,如果你不逃跑的话,你应该走。

    编辑:关于单件,我建议你看看以下问题 this one (在评论中也有一些很好的平衡)。

    让一个对象保持缓存状态本身是可以的,尤其是在EJB3中,您可以注入状态而不是静态引用它(如果使用@service注释,那么您需要@depends jboss特定的注释)。也就是说,如果你在这里使用的是一个“合适的”单件,那么我希望你唯一的问题是,你的战争有两个独立的分类装载机,这是额外的内存足迹。否则,您将进入单例的问题区域(在这里,必须初始化它们才能使用,使用它们的所有内容都必须确保首先初始化它们,当然,所有代码都会与初始化高度耦合)。

    单件子真正糟糕的地方是它们存储状态的地方,这样一个类可以更改状态,另一个类就可以获取状态。在3.1之前,它在EJB中基本上是不允许的,即使这样它也会产生很多并发问题。

    编辑(进一步):所以您希望使用类加载器存储库。我使用JBoss4.2.3,所以我不一定知道JBoss5的所有输入和输出(虽然他们说它几乎完全向后兼容,但它确实重写了它的类加载器),但是在4.2.x中,默认情况下,您的配置不会造成任何问题,因为部署在服务器上的所有EAR都共享同一个类加载器(“统一类加载器”)。我怀疑您要部署的服务器的配置不同,因此我不确定如何与之交互,但您必须在您的耳朵中添加一个名为jboss-app.xml的文件(与application.xml位于同一位置),该文件如下所示:

     <?xml version="1.0"?>
     <!DOCTYPE jboss-app PUBLIC "-//JBoss//DTD J2EE Application 4.2//EN"
            "http://www.jboss.org/j2ee/dtd/jboss-app_4_2.dtd">
     <jboss-app>
          <loader-repository>
          com.yourcomany:archive=yourear
          </loader-repository>
     </jboss-app>
    

    这是针对JBoss4.2的。5.1有相同类型的标签,这里是 xsd . 它具有相同的装载机存储库概念。

    应该 就是它。也就是说,只要您的EJB jar、war等没有它,那么它们就不需要它。但是,您的战争(在jboss-web.xml中-与web.xml位置相同)可能需要相同的东西。在这种情况下,只要您以完全相同的方式命名存储库(如果我理解正确-从未亲自尝试过),它们将共享同一个类加载器。在jboss.xml中配置的EJB与ejb.xml在同一位置上配置的EJB也一样。

    This 可能会更清楚一点。

        2
  •  1
  •   duffymo    15 年前

    我会在你的应用服务器上配置一个单独的对象池,这样它只包含单个实例。

    你为什么要这样做才是真正的问题。听起来你所有的应用程序都将以这种方式耦合。和 Google is eradicating 它的应用程序中的singleton。为什么你觉得合适把它带回来?

        3
  •  1
  •   Guillaume    15 年前

    您可以使用一个MBean并将其绑定到JNDI,然后在任何您想使用它的地方检索它。

    MBean可能部署在.sar文件中

        4
  •  1
  •   Arjan Tijms Mike Van    12 年前

    如果您使用的是Java EE 6,那么它支持singleton EJBs。

        5
  •  0
  •   Will Hartung    15 年前

    如果可行的话,只需将具有singleton的类放入jar中,将jar从EAR中取出,并将jar添加到jboss类加载器中(通过系统类路径或某个lib目录)。这使类成为两次战争共用的一个类加载器。

    单件将无法“看到”任何东西在您的应用程序战争等,因为他们在一个较低的类加载器。

    但是,没有什么能阻止你向singleton(在服务器启动时)中注入一个工厂类,它源自wars等人,并且该类可以访问所有的应用程序类。这使得单体更像一个简单的容器。

    但这很简单。

    此外,如果这样做,请确保在关闭应用程序时释放此单例持有的任何实例。取消部署应用程序时,singleton的任何类引用都不会被gc'd引用。因此,如果您有对存储在singleton中的应用程序的引用,那么服务器将保存对singleton类加载器的引用,该类加载器将保存对singleton类的引用,该类包含对应用程序类加载器的引用,以及对应用程序中所有类的引用。留下一点也不好。

    推荐文章