Pregunta

I creating a Java EE 7 project using Eclipse Maven plugin. My problem is when I run the application the class that implements SerlvetContextListener does not get invoked. What is causing this problem?

@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>
¿Fue útil?

Solución 3

In web.xml you also need to specify the <listener-class>.

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

Otros consejos

To summarize JNL's and Ted Goddard's answers:

For a ServletContextListener (or other listeners, such as a ServletContextAttributeListener or a ServletRequestAttributeListener) to be loaded by the servlet container, you need to tell the container about it. As described in the API docs, there are three ways to do this:

  1. Declare it in the deployment descriptor (web.xml):

    com.kyrogaming.AppServletContextListener
  2. or annotate its class with @WebListener (see "Note about annotations" below)

  3. or register it programatically, via the methods in ServletContext, such as addListener().

Note about annotations

Method 1) and 3) will always work. For method 2) (annotations) to work, the servlet container must be configured to scan the classes in the classpath, to find the annotated listener classes.

The webapp's own classes (under WEB-INF/classes) and libraries (JARs under WEB-INF/lib) will not be scanned if the web.xml contains the attribute metadata-complete="true" (the attribute defaults to false). See the Java Servlet Specification Version 3.0, chapter 8.1, "Annotations and pluggability".

In a web application, classes using annotations will have their annotations processed only if they are located in the WEB-INF/classes directory, or if they are packaged in a jar file located in WEB-INF/lib within the application. The web application deployment descriptor contains a new “metadata-complete” attribute on the web-app element. The “metadata-complete” attribute defines whether the web descriptor is complete, or whether the class files of the jar file should be examined for annotations and web fragments at deployment time. If “metadata-complete” is set to "true", the deployment tool MUST ignore any servlet annotations present in the class files of the application and web fragments. If the metadata-complete attribute is not specified or is set to "false", the deployment tool must examine the class files of the application for annotations, and scan for web fragments.

So, to allow the container to find annotated classes in JARs, make sure the web.xml sets metadata-complete="false", or does not set it at all.

Note that setting this may delay the application startup; see for example What to do with annotations after setting metadata-complete="true" (which resolved slow Tomcat 7 start-up)? .


Unfortunately, that still does not explain why the ServletContextListener in the question is not loaded. Note that the web.xml in the question does not metadata-complete, meaning it defaults to false, thus classpath scanning is enabled. There is probably some other problem; this checklist hopefully helps in finding it.

Using metadata-complete="false" in web.xml fixed this issue for me.

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

For the record, I'm adding yet another possible (and rather vicious) cause of ServletContextListener not being invoked.

This can happen when you have a java.lang.LinkageError, that is when you forgot to add <scope>provided</scope> to your javax.servlet-api dependency. In such a case the listener instance is created but only the static part is executed, not the contextInitialized and contextDestroyed methods.

You shall discover only when you invoke some servlet, as the linkage error is not raised during listener instantiation.

There is one other extremely rare scenario which can cause this. (which took me 4 hours to uncover)

If you're using Tomcat10 then you can't use javax.servlet library in your maven/gradle.

Tomcat9 still has javax.servlet, but Tomcat10 migrated to jakarta.servlet

Tomcat10 expects to have Listener class that uses jakarta.servlet.ServletContextListener

So use this maven dependency: (scope is provided, because Tomcat10 already has such library)

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

The running container might need to explicitly allow scanning for annotations:

Ex for jetty:

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

In a Spring-Boot 1.3+ scenario, you need to have the package for the class annotated with @WebListener (and @WebFilter, @WebServlet) fall under the @ServletComponentScan package scope.

Per Baeldung.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top