ServletContextListener 未被调用

问题描述 投票:0回答:8

我使用 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
8个回答
33
投票

总结 JNL 和 Ted Goddard 的答案:

对于要由 servlet 容器加载的 ServletContextListener(或其他侦听器,例如 ServletContextAttributeListener 或 ServletRequestAttributeListener),您需要将其告知容器。如 API 文档中所述,有三种方法可以实现此目的:

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

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

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

注释注意事项

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

如果 web.xml 包含属性 WEB-INF/classes

(该属性默认为 
WEB-INF/lib
),则不会扫描
webapp 自己的类(在 
metadata-complete="true"
下)和库(在
false
下的 JAR)。请参阅 Java Servlet 规范版本 3.0,第 8.1 章,“注释和可插入性”。

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

因此,为了允许容器在 JAR 中查找带注释的类,请确保 web.xml 设置

metadata-complete="false"
,或者根本不设置它。

注意设置此项可能会延迟应用程序启动;例如,请参阅设置metadata-complete =“true”后如何处理注释(解决了Tomcat 7启动缓慢的问题)?.


不幸的是,这仍然不能解释为什么问题中的 ServletContextListener 没有加载。请注意,问题中的 web.xml 不是

metadata-complete
,这意味着它默认为
false
,因此启用了类路径扫描。可能还有其他问题;这个清单希望有助于找到它。


14
投票

在 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">

8
投票

在 web.xml 中,您还需要指定

<listener-class>

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

3
投票

为了记录,我添加了另一个可能的(而且相当恶毒的)原因

ServletContextListener
未被调用。

当您有

java.lang.LinkageError
时,即您忘记将
<scope>provided</scope>
添加到
javax.servlet-api
依赖项时,就会发生这种情况。 在这种情况下,会创建侦听器实例,但仅执行静态部分,而不执行
contextInitialized
contextDestroyed
方法。

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


2
投票

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

如果您使用的是 Tomcat10,那么您无法在 maven/gradle 中使用

javax.servlet
库。

Tomcat9 仍然有

javax.servlet
,但 Tomcat10 迁移到
jakarta.servlet

Tomcat10 期望有使用

jakarta.servlet.ServletContextListener

的监听器类

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

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

0
投票

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

例如码头:

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

0
投票

在Spring-Boot 1.3+场景中,需要将@WebListener(和@WebFilter、@WebServlet)注释的类的包置于@ServletComponentScan包范围内。

Per Baeldung


0
投票

虽然参加聚会已经很晚了,但我想添加帮助我的答案:

您缺少零参数公共构造函数。添加后,无论以何种方式注册,WebListener 都会被调用。一个简单的

public ApplicationContextListener() {}

将在你的情况下解决问题。

请参阅 Servlet 规范 的第 4.4.3.4 节,了解其中规定的详细信息

给定的 EventListener 类必须定义零参数 构造函数,用于实例化它。

© www.soinside.com 2019 - 2024. All rights reserved.