19

我使用 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) 
    {

    }

}

网页.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>
4

6 回答 6

29

总结 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 包含属性(属性默认为) ,则不会扫描webapp 自己的类(在 下WEB-INF/classes)和库(在 下的 JARWEB-INF/libmetadata-complete="true"false)。请参阅Java Servlet 规范版本 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”,

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

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


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

于 2016-04-12T08:26:34.767 回答
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">
于 2014-03-03T17:43:07.250 回答
8

在 web.xml 中,您还需要指定<listener-class>.

    <listener>
        <listener-class>
                 com.kyrogaming.AppServletContextListener
        </listener-class>
    </listener>
于 2013-08-21T21:00:06.840 回答
2

作为记录,我正在添加另一个可能(而且相当恶毒)的原因,即ServletContextListener没有被调用。

当你有一个 时,这可能会发生java.lang.LinkageError,即当你忘记添加<scope>provided</scope>你的javax.servlet-api依赖项时。在这种情况下,创建了侦听器实例,但只执行静态部分,而不是contextInitializedandcontextDestroyed方法。

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

于 2016-06-02T16:50:45.423 回答
0

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

例如码头:

cd [JETTY_BASE]
java -jar [JETTY_HOME]/start.jar --add-module=annotations
于 2020-12-30T11:35:41.777 回答
0

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

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

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

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

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

        <dependency>
            <groupId>jakarta.servlet</groupId>
            <artifactId>jakarta.servlet-api</artifactId>
            <version>5.0.0</version>
            <scope>provided</scope>
        </dependency>
于 2021-05-11T08:34:19.907 回答