【问题标题】:ServletContextListener not being invoked未调用 ServletContextListener
【发布时间】:2013-08-24 10:05:29
【问题描述】:

我使用 Eclipse Maven 插件创建了一个 Java EE 7 项目。我的问题是当我运行应用程序时,实现 SerlvetContextListener 的类不会被调用。是什么导致了这个问题?

@WebListener
public class ApplicationContextListener implements ServletContextListener{

    @Override
    public void contextInitialized(ServletContextEvent sce)
    {
        Request request = new HttpRequest(sce);
        new Thread (request).start();
        HibernateUtil.getSessionFactory();
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) 
    {

    }

}

web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app 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-app_3_1.xsd"
         version="3.1">
    <listener>com.kyrogaming.AppServletContextListener</listener>
    <!-- Jersey Mapping -->
    <servlet>
        <servlet-name>jersey-servlet</servlet-name>
        <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
        <init-param>
            <param-name>com.sun.jersey.config.property.packages</param-name>
            <param-value>com.kyrogaming.webservices</param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>jersey-servlet</servlet-name>
        <url-pattern>/service/*</url-pattern>
    </servlet-mapping>
    <!-- end Jersey Mapping -->

    <welcome-file-list>
        <welcome-file>index.html</welcome-file>
    </welcome-file-list>
</web-app>

【问题讨论】:

    标签: servlets servlet-listeners


    【解决方案1】:

    总结 JNL 和 Ted Goddard 的回答:

    对于要被 servlet 容器加载的 ServletContextListener(或其他侦听器,例如 ServletContextAttributeListener 或 ServletRequestAttributeListener),您需要将其告知容器。作为described in the API docs,有三种方法可以做到这一点:

    1. 在部署描述符(web.xml)中声明:

      com.kyrogaming.AppServletContextListener
    2. @WebListener注释它的类(参见下面的“关于注释的注释”)

    3. 通过 ServletContext 中的方法以编程方式注册它,例如 addListener()

    注释说明

    方法 1) 和 3) 将始终有效。要使方法 2)(注解)起作用,必须将 servlet 容器配置为扫描类路径中的类,以查找带注解的侦听器类。

    如果 web.xml 包含属性metadata-complete="true"(该属性默认为@ 987654330@)。请参阅Java Servlet Specification Version 3.0,第 8.1 章,“注解和可插拔性”。

    在 Web 应用程序中,使用注解的类只有在它们位于 WEB-INF/classes 目录中,或者如果它们被打包在应用程序内的 WEB-INF/lib 中的 jar 文件中时,才会处理它们的注解。 Web 应用程序部署描述符在 web-app 元素上包含一个新的“元数据完整”属性。 “metadata-complete”属性定义了 web 描述符是否完整,或者是否应该在部署时检查 jar 文件的类文件中的注释和 web 片段。如果“metadata-complete”设置为“true”,部署工具必须忽略应用程序和 web 片段的类文件中存在的任何 servlet 注释。如果未指定 metadata-complete 属性或设置为“false”,则部署工具必须检查应用程序的类文件中的注释,并扫描 Web 片段。

    因此,要允许容器在 JAR 中找到带注释的类,请确保 web.xml 设置为 metadata-complete="false",或者根本不设置它。

    请注意,设置此项可能会延迟应用程序启动;例如见What to do with annotations after setting metadata-complete="true" (which resolved slow Tomcat 7 start-up)?


    不幸的是,这仍然不能解释为什么没有加载问题中的 ServletContextListener。请注意,问题中的 web.xml 不是metadata-complete,这意味着它默认为false,因此启用了类路径扫描。可能还有其他问题;希望这份清单有助于找到它。

    【讨论】:

      【解决方案2】:

      在 web.xml 中使用 metadata-complete="false" 为我解决了这个问题。

      <web-app 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-app_3_1.xsd"
        version="3.1"
        metadata-complete="false">
      

      【讨论】:

        【解决方案3】:

        在 web.xml 中还需要指定&lt;listener-class&gt;

            <listener>
                <listener-class>
                         com.kyrogaming.AppServletContextListener
                </listener-class>
            </listener>
        

        【讨论】:

        • 这是不真实的。从 Java EE 6 开始,您可以使用 @WebListener 注册它们,而无需任何 web.xml 条目。请及时赶上,Java EE 6 自 2009 年 12 月就已经发布了。这也适用于错误地支持这个错误答案的人。
        • 根据目前提供的信息无法回答问题。如果我猜的话,那么那个监听器根本就没有真正结束在运行时类路径中。
        【解决方案4】:

        为了记录,我要添加另一个可能(而且相当恶毒)的原因,导致 ServletContextListener 未被调用。

        当您有 java.lang.LinkageError 时会发生这种情况,即您忘记将 &lt;scope&gt;provided&lt;/scope&gt; 添加到您的 javax.servlet-api 依赖项时。 在这种情况下,会创建监听器实例,但只执行静态部分,而不是 contextInitializedcontextDestroyed 方法。

        只有在调用某个 servlet 时才会发现,因为在侦听器实例化期间不会引发链接错误。

        【讨论】:

          【解决方案5】:

          正在运行的容器可能需要明确允许扫描注释:

          例如码头:

          cd [JETTY_BASE]
          java -jar [JETTY_HOME]/start.jar --add-module=annotations
          

          【讨论】:

            【解决方案6】:

            还有另一种极其罕见的情况会导致这种情况。 (我花了 4 个小时才发现)

            如果您使用的是 Tomcat10,则不能在 maven/gradle 中使用 javax.servlet 库。

            Tomcat9还有javax.servlet,但是Tomcat10迁移到jakarta.servlet

            Tomcat10 期望有使用 jakarta.servlet.ServletContextListener 的 Listener 类

            所以使用这个maven依赖:(提供范围,因为Tomcat10已经有这样的库)

                    <dependency>
                        <groupId>jakarta.servlet</groupId>
                        <artifactId>jakarta.servlet-api</artifactId>
                        <version>5.0.0</version>
                        <scope>provided</scope>
                    </dependency>
            

            【讨论】:

              猜你喜欢
              • 2015-09-03
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2012-06-02
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多