java.lang.IllegalArgumentException:WFLYWELD0037:将持久性单元注入 CDI 托管 bean 时出错

Posted

技术标签:

【中文标题】java.lang.IllegalArgumentException:WFLYWELD0037:将持久性单元注入 CDI 托管 bean 时出错【英文标题】:java.lang.IllegalArgumentException: WFLYWELD0037: Error injecting persistence unit into CDI managed bean 【发布时间】:2021-02-27 23:33:03 【问题描述】:

我看到的错误类似于here 记录的错误。但是,我的 EAR 和 WAR 项目之间没有直接的 ejb 注入。

环境: 应用服务器:JBoss EAP 7.3

我将项目设置为: EJB-EAR:

包含一个包含所有 DAO 对象、JPA 相关内容和 persistence.xml 的 DataManagement.jar persistence.xml 位于 jar 内的 main/resources/META-INF/ 下

persistence.xml:

<persistence version="2.1"
   xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="
        http://xmlns.jcp.org/xml/ns/persistence
        http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
   <persistence-unit name="primary">
      <!-- If you are running in a production environment, add a managed
         data source, this example data source is just for development and testing! -->
      <jta-data-source>java:jboss/datasources/PcosDS</jta-data-source>
      <properties>
         <!-- Properties for Hibernate -->
         <property name="hibernate.hbm2ddl.auto" value="create-drop" />
         <property name="hibernate.show_sql" value="false" />
      </properties>
   </persistence-unit>
</persistence>

一个示例 DAO 对象看起来像

 @Stateless
 public class LoginAttemptDAO 
    
     private static final ILogger logger = LoggerFactory
                .getLogger(LoginAttemptDAO.class);
    
     @Inject
     private EntityManager entityManager;

生产者定义为:

public class Resources 
      @Produces
      @PersistenceContext(unitName="primary")
      private EntityManager em;

战争:

WAR 项目启动应用程序并在其 WEB-INF/lib 中包含其他 jar。其中一个 jar 最终通过 EJB 查找访问 EAR 项目中的 jar。 WAR 包含 /src/main/webapp/META-INF 下的 jboss-deployment-structure.xml 和 jboss-all.xml

jboss-deployment-structure.xml

<jboss-deployment-structure xmlns="urn:jboss:deployment-structure:1.2">
    <deployment>
        <dependencies>            
            <module name="deployment.pts-ear-1.0-SNAPSHOT.ear.DataManagement.jar"/>
        </dependencies>
        <exclusions>
        
        </exclusions>
    </deployment>
</jboss-deployment-structure>

jboss-all.xml

<jboss umlns="urn:jboss:1.0">
    <jboss-deployment-dependencies xmlns="urn:jboss:deployment-dependencies:1.0">
        <dependency name="pts-ear-1.0-SNAPSHOT.ear" />
    </jboss-deployment-dependencies>
</jboss>

EAR 部署良好,我确实看到测试数据库预先填充了初始数据。一旦我部署战争项目,问题就会出现,我看到的错误是

引起:java.lang.IllegalArgumentException:WFLYWELD0037:错误 将持久性单元注入 CDI 托管 bean。找不到一个 部署中名为“主要”的持久性单元 InitializeServlet-war-1.0-SNAPSHOT.war 用于注入点私有 javax.persistence.EntityManager com.lmco.pts.pcos.inf.DataManagement.dao.Resources.em 在 org.jboss.as.weld.jpa@7.3.0.GA-redhat-00004//org.jboss.as.weld.services.bootstrap.WeldJpaInjectionServices.getScopedPUName(WeldJpaInjectionServices.java:105) 在 org.jboss.as.weld.jpa@7.3.0.GA-redhat-00004//org.jboss.as.weld.services.bootstrap.WeldJpaInjectionServices.registerPersistenceContextInjectionPoint(WeldJpaInjectionServices.java:68) 在 org.jboss.weld.core@3.1.2.Final-redhat-00001//org.jboss.weld.injection.ResourceInjectionFactory$PersistenceContextResourceInjectionProcessor.getResourceReferenceFactory(ResourceInjectionFactory.java:174) 在 org.jboss.weld.core@3.1.2.Final-redhat-00001//org.jboss.weld.injection.ResourceInjectionFactory$PersistenceContextResourceInjectionProcessor.getResourceReferenceFactory(ResourceInjectionFactory.java:162)

如果我将 DataManagement.jar 打包在 WAR 项目的 WEB-INF/lib 中,则一切正常。我正在尝试将 DataManagement.jar 从战争项目中移出,以便它可以被其他项目使用,并作为部署在应用程序服务器上的其他项目的动态资源。我怀疑持久性单元对 WAR 不可见,但 WAR 并不真正需要持久性单元。它只是从执行数据库访问的 JAR 调用服务。

【问题讨论】:

DataManagement.jar 和 WAR 在同一个 EAR 中吗? 只有 DataManagement.jar 被打包在 EAR 中。这个想法是允许多个 WAR 访问同一个 jar。实际上我设法解决了这个问题,它与 beans.xml 和生产者类的组合有关。我会尽快发布解决方案。 【参考方案1】:

如果我理解正确,您假设单独的 JAR 是您可以参考的专用部署,但事实并非如此。持久性单元必须是部署的一部分。也许可以为 JAR 创建一个 JBoss 模块并引用它,但最后,它将为每个引用该模块的部署启动持久性单元。将 JAR 放入 WEB-INF/lib 有什么问题?您也可以将 JAR 打包到其他 WAR 中。

【讨论】:

【参考方案2】:

原来我没有发布的缺失信息之一是 DataManagement.jar 的 beans.xml 配置。它的 bean 发现模式设置为 all 以允许发现未注释的生产者类 Resource:

<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="
      http://xmlns.jcp.org/xml/ns/javaee
      http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
    bean-discovery-mode="all">
</beans>

删除此文件后(最新的 CDI 不需要此文件,默认情况下 bean 发现模式设置为带注释)或将发现模式更改为“带注释”并将生产者类注释为:

@Stateless
public class Resources 
      @PersistenceContext(unitName="primary")
      private EntityManager em;
      
      @Produces
      public EntityManager entityManager()
          return em;
      

部署的 WAR 能够通过执行 ejb 查找成功访问 DataManagement.jar。

【讨论】:

以上是关于java.lang.IllegalArgumentException:WFLYWELD0037:将持久性单元注入 CDI 托管 bean 时出错的主要内容,如果未能解决你的问题,请参考以下文章

IllegalArgumentException:此 NavController 未知导航目的地 xxx