【问题标题】:How do I make JNDI names compatible with both GlassFish and WildFly如何使 JNDI 名称与 GlassFish 和 WildFly 兼容
【发布时间】:2026-01-07 11:15:01
【问题描述】:

我正在开发一个 Java EE 7 应用程序,并且需要将该应用程序部署到运行 GlassFish 4.0 或 WildFly 8.1.0 的应用程序服务器上。我遇到的问题是 GlassFish 和 WildFly 对 JNDI 名称使用的格式略有不同,但我不知道如何使我的应用程序与两者兼容。

在 GlassFish 中,我的 persistence.xml 文件引用数据源 jdbc/myDataSouce,但在 WildFly 中,数据源需要是 java:/jdbc/myDataSource。

对于使用@Resource 注解的类也是如此。在 GlassFish 中,使用 JavaMail 的类的注释是 @Resource(name = "mail/myMailSession"),但要部署到 WildFly,这需要是 @Resource(name = "java:mail/myMailSession")。

我知道我可以解压缩 EAR 和 JAR 文件以手动编辑文件,例如 persistence.xml,但我不能对使用 @Resource 注释的类执行此操作。

有没有一种方法可以让我将已编译的应用程序部署到 GlassFish 和 WildFly 上,而无需维护两个不同版本的代码?我假设答案可能在于特定于应用程序的部署描述符,但我找不到任何涵盖这两种情况的示例。

谁能指点我正确的方向?

【问题讨论】:

    标签: java jakarta-ee glassfish jndi wildfly


    【解决方案1】:

    您可以修改 Wildfly JNDi 名称并从各自的 JNDI 名称中去除不需要的前缀,以在两个应用服务器中找到最小公分母。以下适用于 Glassfish 和 JBoss AS 7.1。由于我希望 Wildfly 在这方面向后兼容 JBoss,我想它也适用于 Wildfly。

    持久性

    注入为:

    @PersistenceContext(unitName="TestPU")
    private EntityManager entityManager;
    

    或通过ejb-jar.xml:

    <persistence-context-ref>
        <persistence-context-ref-name>entityManager</persistence-context-ref-name>
        <persistence-unit-name>TestPU</persistence-unit-name>
        <injection-target> ... </injection-target>
    </persistence-context-ref>
    

    对应的persistence.xml

    <persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="         http://java.sun.com/xml/ns/persistence         http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
      <persistence-unit name="TestPU" transaction-type="JTA">
        <jta-data-source>datasources/TestDS</jta-data-source>
        <class>org.jeeventstore.persistence.jpa.EventStoreEntry</class>
        <properties>
          <property name="hibernate.show_sql" value="false"/>
          <property name="hibernate.format_sql" value="true"/>
          <property name="hibernate.hbm2ddl.auto" value="create-drop"/>
          <property name="hibernate.connection.charSet" value="UTF-8"/>
          <property name="eclipselink.logging.level" value="FINE"/>
          <property name="eclipselink.logging.level.sql" value="FINE"/>
          <property name="eclipselink.logging.parameters" value="true"/>
          <property name="eclipselink.ddl-generation" value="drop-and-create-tables"/>
        </properties>
      </persistence-unit>
    </persistence>
    

    (注意简单的jta-data-sourceJNDI 名称)

    这是一个glassfish-resources.xml 文件,用于指定部署时的 Derby 数据库,类似的设置可用于 MySQL 或 Postgres。

    <resources>
    
        <jdbc-resource pool-name="ArquillianEmbeddedDerbyPool"
                       jndi-name="datasources/TestDS"/>
    
        <jdbc-connection-pool name="ArquillianEmbeddedDerbyPool"
                              res-type="javax.sql.DataSource"
                              datasource-classname="org.apache.derby.jdbc.EmbeddedDataSource"
                              is-isolation-level-guaranteed="false">
            <property name="databaseName" value="target/databases/derby"/>
            <property name="createDatabase" value="create"/>
        </jdbc-connection-pool>
    
    </resources>
    

    还有来自 JBoss standalone.xml 的设置:

    <datasource jta="true" jndi-name="java:/datasources/TestDS" pool-name="TestDS" enabled="true" use-ccm="false">
        <connection-url>jdbc:postgresql://localhost/test_db</connection-url>
        ...
    </datasource>
    

    资源

    我没有在 Glassfish 上注入 JavaMail 组件,但类似于数据源设置,可能值得尝试从 @Resource 注释中剥离“java:”部分。

    @Resource(name = "mail/myMailSession")
    

    然后配置 Wildfly,使邮件资源在“java:mail/myMailSession”JNDI 位置可用。

    通过ejb-jar.xml注入

    另一种选择是通过ejb-jar.xml 文件手动注入字段,然后使用构建工具(如maven)在组装时将ejb-jar-glassfish.xmlejb-jar-wildfly.xml 复制到所需的ejb-jar.xml

    在我们的一个项目中,我们使用混合方法来避免 xml 配置的负担:我们通过 ejb-jar.xml 配置少量“提供者”bean 来注入,例如,持久性上下文到 PersistenceContextProvider,然后使用 CDI 通过@EJBPersistenceContextProvider 注入到EJB 中,因为它们驻留在同一个EAR 中,所以无需进一步配置即可找到。

    【讨论】:

      【解决方案2】:

      我还没有遇到邮件困境。但是我在数据源定义方面遇到了同样的问题,我的解决方案是不使用服务器的控制台设置数据源,而是使用 @DataSourceDefinition 注释使它们与您的存档一起部署。事实证明,如果在部署期间设置了数据源,WildFly 不会抱怨 java:app/blabla..

      这是一个适用于 GlassFish 和 WildFly 的真实示例:

      https://github.com/martinanderssondotcom/java-ee-concepts/../ArquillianDS.java

      注意声明的数据源JNDI名称是:

      java:app/env/ArquillianDS

      这里是相关的persistence.xml文件(不要介意这个存储库中的文件名,存储库代表一个在运行时构建档案的测试项目,应用程序将更改档案中文件的名称到persistence.xml):

      https://github.com/MartinanderssonDotcom/java-ee-concepts/../persistence-update.xml

      另外请注意,持久化单元需要使用此 JNDI 名称定位的数据源:

      java:app/env/ArquillianDS

      此部署与 GlassFish 和 WildFly 完美配合。我已经注意到,如果我们在部署期间声明数据源,那么我们会付出在管理 gui/控制台的任何地方都看不到列出的数据源的代价。对我来说,为了拥有一个真正可移植的应用程序,这是一个很小的代价。作为额外的奖励,我不必编写冗长的安装/设置说明。对于我所有的项目,数据源是应用程序的固有部分,我不介意在存档中有一个代表数据源的类文件。

      上述数据源使用的是 Java DB(或老派人士的“Apache Derby”)。正如 ArquillianDS.java 文件中的一些 cmets 所描述的:GlassFish 在使用结合 Java DB 的简单 URL 连接字符串时存在问题。因此,我求助于明确指定 @DataSourceDefinition 的所有属性。最近在我的另一个项目(可惜不是公共项目)中,我使用了相同的部署时间数据源定义构造,但针对的是 MySQL。这是数据源定义,它适用于两台服务器:

      @DataSourceDefinition(
              name = "java:app/env/maLivechatDS",
              url = "jdbc:mysql://localhost:3306/malivechat_db?createDatabaseIfNotExist=true&user=root&password",
              className = "com.mysql.jdbc.jdbc2.optional.MysqlDataSource"
      )
      @ManagedBean
      public class MySQLDataSource { }
      

      请注意,驱动程序是MysqlDataSource 而不是MysqlXADataSource。我的应用程序中的一个点使用了相当复杂的事务方案,如果我使用 XA 驱动程序,GlassFish 就会遇到问题。但是,我的应用程序使用的非 XA 驱动程序仍然可以在 JTA 事务中正常工作,所以对我来说,这只是一个让船漂浮的廉价技巧。您可能应该使用 XA 驱动程序。

      【讨论】:

      • 这似乎对我不起作用,因为 Wildly 在执行 Arquillian Junit 测试时没有检测到这一点
      【解决方案3】:

      对于带有可移植 DataSourceDefinition 注释的 JNDI 可移植性,我在 payara-5.192、wildfly-17.0.1、tomee-8-M3 和 openLiberty-19.0.0.7 上对其进行了测试

      @DataSourceDefinition(
      name = "java:app/env/jdbc/mysql_app_name",
      className = "com.mysql.cj.jdbc.MysqlConnectionPoolDataSource",
      url = "jdbc:mysql://localhost:3306/db_name?characterEncoding=utf-8&zeroDateTimeBehavior=CONVERT_TO_NULL&user=root&password=password",
      minPoolSize = 1,
      properties = {"characterEncoding=utf-8","zeroDateTimeBehavior=CONVERT_TO_NULL"})
      

      我将它与 MySQL 连接器 8 一起使用。 请参阅reference。对于 wildfly,我创建了一个用于配置的启动 bean 类并在启动类中设置注释。 为 openLiberty 添加 server.xml

      <application id="app_name" contextRoot="/app_name" name="app_name" location="../app_name.war" type="war">
        <classloader commonLibraryRef="mysql"/>
      </application>
      <library id="mysql">
          <file name="/path_to/mysql-connector-java-8.0.17.jar"/>
      </library>
      

      并将war文件放入

      usr/servers/defaultServer

      文件夹

      【讨论】: