如何在Tomcat上安装和使用CDI?

Posted

技术标签:

【中文标题】如何在Tomcat上安装和使用CDI?【英文标题】:How to install and use CDI on Tomcat? 【发布时间】:2013-09-30 12:22:38 【问题描述】:

我正在创建我的第一个项目 Java EE 7,但遇到了麻烦。感谢任何帮助。

Tomcat 7.0.34 JSF 2.2 Primefaces 3.5 javaee-api-7.0.jar

应用程序启动时,Tomcat 日志显示以下消息:

"validateJarFile (C:\...\build\web\WEB-INF\lib\javaee-api-7.0.jar)-jar not loaded. See Servlet 2.3 Spec, section 9.7.2. Offending class: javax/servlet/Servlet .class"

当我单击调用托管 bean 的按钮时,出现错误:

Advertência: /index.xhtml @18,66 value="#indexMB.user": Target Unreachable, identifier 'indexMB' resolved to null
javax.el.PropertyNotFoundException: /index.xhtml @18,66 value="#indexMB.user": Target Unreachable, identifier 'indexMB' resolved to null

索引MB

@Named("indexMB")
@RequestScoped
public class IndexMB 

private String password;
private String user;

public String loginTest()
    return (this.user.equals("admin") ? "adminPage" : "inOutPage");


// getters and setters

index.xhtml

<html ...>

<f:loadBundle basename="i18n" var="bundle" />
<h:head>
    <title>#bundle['index_title']</title>
</h:head>
<h:body>
    #bundle['index_appname']
    <br />
    <h:form id="frmIndex">
        <p:panelGrid columns="2">
            <p:outputLabel for="user" value="#bundle['lblUser']" />
            <p:inputText id="user" value="#indexMB.user" />

            <p:outputLabel for="password" value="#bundle['lblPassword']" />
            <p:password id="password" value="#indexMB.password" />
        </p:panelGrid>
        <p:commandButton action="#indexMB.loginTest" value="#bundle['btn_login']" />
    </h:form> 
</h:body>

faces-config.xml

<?xml version='1.0' encoding='UTF-8'?>
<faces-config version="2.2"
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/web-facesconfig_2_2.xsd">

<application>
    <locale-config>
        <default-locale>pt_BR</default-locale>
        <supported-locale>en</supported-locale>
        <supported-locale>fr</supported-locale>
    </locale-config>
</application>

这些话题对我没有帮助:

Java EE 6 @javax.annotation.ManagedBean vs. @javax.inject.Named vs. @javax.faces.ManagedBean Target Unreachable identifier resolved to null Target Unreachable, identifier resolved to null javax.el.PropertyNotFoundException : Target Unreachable, identifier 'login' resolved to null Spring + JSF http://www.andrejkoelewijn.com/blog/2010/03/05/jee-cdi-tip-target-unreachable-identifier-resolved-to-null/

【问题讨论】:

显示你的faces-config.xml文件 感谢@Kalathoki,已添加文件。几乎没有,因为我正在使用注释。 确保indexMB bean 构造成功。 【参考方案1】:

Tomcat 作为准系统 JSP/Servlet 容器不支持开箱即用的 CDI。您究竟是如何安装 CDI 的?您是否真的将jakartaee-api.jarjavaee-api.jar 放入/WEB-INF/lib 只是为了让您的代码编译?哦,请不要,这不是正确的方法。 JEE API JAR 仅包含 API 类,不包含具体实现。摆脱整个 JAR。它可能会导致许多其他可移植性问题,例如此答案中描述的问题:How do I import the javax.servlet / jakarta.servlet API in my Eclipse project? 您实际上应该安装具体的实现以及特定的 API。

你有两个选择:

    放弃 Tomcat 并选择真正的 Jakarta EE 容器。当您使用 Tomcat 时,只需转到TomEE。真的很简单,download the TomEE web profile zip file,提取它并将其集成到 Eclipse 中,就像您为 Tomcat 所做的那样。不要忘记从 webapp 中删除 Jakarta EE JAR 文件并将项目属性中的 Targeted Runtime 属性从 Tomcat 更改为 TomEE,以便正确解决 Jakarta EE 依赖项。另见What exactly is Java EE?

    不需要额外的 JAR 或配置。您甚至可以从您的 web 应用程序中删除手动安装的 JSF/JSTL/CDI/BV/JPA/EJB/JTA/JSONPJAX-RS/etc/etc 库。作为真正的 Jakarta EE 容器,TomEE 已经为它们提供了开箱即用的功能。如果你使用的是 Maven,下面的坐标就足够了。

     <dependency>
         <groupId>jakarta.platform</groupId>
         <artifactId>jakarta.jakartaee-web-api</artifactId>
         <version><!-- e.g. 9.0.0 --></version>
         <scope>provided</scope>
     </dependency>
    

    请注意provided 的重要性及其在“目标运行时已提供此功能”中的含义。有关 Tomcat 和普通 JEE 容器的详细 pom.xml 示例,另请参阅 Tomcat casting servlets to javax.servlet.Servlet instead of jakarta.servlet.http.HttpServlet。


    在 Tomcat 上安装真正的 CDI 实现。以下说明假设 Tomcat 10+。 Weld 是可用的 CDI 实现之一。在the Weld installation guide 中,您可以找到如何将其集成到 Tomcat 中的说明。为了完整起见和将来参考,以下是步骤:

      在 webapp 的 /WEB-INF/lib 中删除 weld-servlet-shaded.jar。如果您使用 Maven,请使用 this coordinate:

       <dependency>
           <groupId>org.jboss.weld.servlet</groupId>
           <artifactId>weld-servlet-shaded</artifactId>
           <version>4.0.0.Final</version>
       </dependency>
      

      在 webapp 中创建 /META-INF/context.xml 文件,内容如下:

       <Context>
           <Resource name="BeanManager" 
               auth="Container"
               type="jakarta.enterprise.inject.spi.BeanManager"
               factory="org.jboss.weld.resources.ManagerObjectFactory"/>
       </Context>
      

      请注意,当您使用 Mojarra 2.2.11 或更高版本时,此步骤并非绝对必要,因为当 JNDI 中不存在时,它将能够通过 ServletContext 找到它。

      在 webapp 中创建一个/WEB-INF/beans.xml 文件。可以留空。

    就是这样(注意:在较旧的 Weld Servlet 版本中,您还需要在 web.xml 中显式注册 CDI bean 管理器和 Weld 侦听器,但当前版本不需要这样做)。

    如果您更喜欢 OpenWebBeans 而不是 Weld 作为 CDI 实现,或者需要在 Tomcat 9.x 或更早版本中安装 CDI,请访问此博客以获取详细的 Maven 安装说明:How to install CDI in Tomcat?


与具体问题无关,Tomcat 7 的 JSP/Servlet API 遵循 Java EE 7 的那些 API,而是遵循 Java EE 6 (Servlet 3.0 /JSP 2.2)。如果您想要与 Java EE 7 (Servlet 3.1 / JSP 2.3) 等效的 Tomcat,那么您应该查看 Tomcat 8。另请参阅 Apache Tomcat version matrix。

【讨论】:

正如我所说,“这是我的第一个 Java EE 7 项目”。非常感谢。 我切换到 TomEE,但初始化它显示以下错误:com.sun.faces.config.ConfigurationException: Factory 'javax.faces.application.ApplicationFactory' was not configured properly. 我看到了主题 could not find Factory: javax.faces.context.FacesContextFactory,但它没有帮助。有没有cmets? 我切换到 Glassfish 4 并收到相同的初始错误 (Target Unreachable, identifier 'indexMB' resolved to null)。我删除了 javaee-api-7.0.jar 。评论? 至于 TomEE,它已经捆绑了 JSF (MyFaces)。如果您仍然在您的 webapp 中捆绑另一个 JSF impl,那么您会得到这个异常。只需从您的 web 应用程序中删除 JSF JAR。至于 GlassFish 4,不确定,但它也可能是由脏类路径引起的。 进行中。 ... TomEE 上的启动错误停止了,但现在 JSF 没有加载(尽管日志上没有显示错误)。 GlassFish 保持初始错误。加载的唯一库是:primefaces-3.5.jar、commons-io.jar、commons-fileupload.jar【参考方案2】:

其他可能的选择是将 beans.xml 留在您的部署中。

【讨论】:

以上是关于如何在Tomcat上安装和使用CDI?的主要内容,如果未能解决你的问题,请参考以下文章

无法将 JSF + CDI 项目从 Tomcat 迁移到 Wildfly

如何在 CDI 中使用 MyBatis

resteasy-cdi 中断部署到 Tomcat 7

如何使用 CDI 进行方法参数注入?

图文如何在centos上安装tomcat

如何在CentOS上安装Tomcat