ServletContainerInitializer vs ServletContextListener

Я пытаюсь зарегистрировать сервлет, используя servletContainerInitializer, но он, похоже, не работает. Может быть, это мой код (любезно просмотрите его), но я подумал о различии между ServletContainerInitializer и ServletContextListener, потому что код follwing отлично работает при использовании вместо ServletContextListener.

Из спецификации сервлета 3.0:

4.4

Способы настройки (добавление сервлетов динамически):

... или из метода onStartup реализации ServletContainerInitializer...

ServletContainerInitializer:

package com.marmoush.javaexamples.nullhaus.servlet;

import java.util.Set;
import javax.servlet.ServletContainerInitializer;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;

public class MyInit implements ServletContainerInitializer {
    public void onStartup(Set<Class<?>> c, ServletContext ctx) throws ServletException {
        System.out.println("hello");
        ServletRegistration reg = ctx.addServlet("q31","com.marmoush.javaexamples.nullhaus.servlet.Q31");
        reg.addMapping("/q31/*");
    }
}

Сервлет, который я пытаюсь автозарегистрировать:

package com.marmoush.javaexamples.nullhaus.servlet;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class Q31 extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.getWriter().println("hello world");
    }
}

Исходный код из nullhaus java example веб-сайт "только имя класса редактируется" также не работает!

package com.marmoush.javaexamples.nullhaus.servlet;

import java.util.Set;

import javax.servlet.Servlet;
import javax.servlet.ServletContainerInitializer;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;

public class MyInit implements ServletContainerInitializer {
    public void onStartup(Set<Class<?>> c, ServletContext ctx) throws ServletException {
        try {
            Class klass = Class.forName("com.marmoush.javaexamples.nullhaus.servlet.Q31");
            Class<Q31> clazz = (Class<Q31>) klass;
            Servlet s = ctx.createServlet(clazz);
            ServletRegistration.Dynamic d = ctx.addServlet("q31", s);
            d.addMapping("/baz/*");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

Ответ 1

Реализация ServletContainerInitializer предназначена для добавления в файл JAR, который, в свою очередь, был сброшен в /WEB-INF/lib веб-приложения. Сам файл JAR должен иметь файл /META-INF/services/javax.servlet.ServletContainerInitializer, содержащий FQN реализации ServletContainerInitializer в JAR. Обратите внимание, что этот файл не должен быть помещен в сам webapp!

Это позволяет разработчикам модуля webapp разрешить их JAR файл подключаться к запуску и выключению webapp. Это правда, что они могли также использовать ServletContextListener с @WebListener для этого, но это не сработает, если собственный файл web.xml для webapp имеет атрибут metadata-complete="true", установленный в <web-app>, что означает, что webapp shouldn 't сканировать JAR для аннотаций (что экономит время запуска).

То, что ServletContainerInitializer не работает в вашем конкретном случае, может означать, что вы фактически не разрабатываете JAR файл модуля, а просто часть, неотъемлемую для вашего собственного веб-приложения. В этом случае ServletContainerInitializer бесполезно для вас, и вместо этого вы должны использовать ServletContextListener.

@WebListener
public class Config implements ServletContextListener {

    @Override
    public void contextInitialized(ServletContextEvent event) {
        // Do stuff during server startup.
    }

    @Override
    public void contextDestroyed(ServletContextEvent event) {
        // Do stuff during server shutdown.
    }

}

См. также:

Ответ 2

Проверьте, правильно ли вы настроили ServletContainerInitializer. Имя класса ServletContainerInitializer должно быть сконфигурировано внутри файла:

META-INF/services/javax.servlet.ServletContainerInitializer

Файл должен содержать только имя класса. Для Ex в вашем случае это должно выглядеть так:

com.marmoush.javaexamples.nullhaus.servlet.MyInit

Файл (META-INF/services/javax.servlet.ServletContainerInitializer) можно связать в библиотеке JAR в WEB-INF/lib.

Вот какой пример, который объясняет.