【问题标题】:ServletContainerInitializer vs ServletContextListenerServletContainerInitializer 与 ServletContextListener
【发布时间】:2012-06-02 08:17:43
【问题描述】:

我正在尝试使用 servletContainerInitializer 注册一个 servlet,但它似乎不起作用,也许这是我的代码(请查看它),但我开始想知道 ServletContainerInitializerServletContextListener 之间的区别,因为以下代码在用作 ServletContextListener 时运行良好。

来自 servlet 3.0 规范:

4.4

配置方法(动态添加servlet):

...或来自ServletContainerInitializer 实现的onStartup 方法...

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/*");
    }
}

我正在尝试自动注册的 servlet:

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 示例网站“仅编辑类名”的原始代码也不起作用!

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();
        }
    }
}

【问题讨论】:

  • 您的 ContainerInitializer 是否正在加载?您是否配置了 ContainerInitialzier?
  • @RameshPVK 不,实际上我没有配置它,你能告诉我怎么做吗?或指向我的链接?
  • 那么你见过 System.out.println("hello");印刷
  • 已添加答案,请查看。

标签: servlets initialization


【解决方案1】:

ServletContainerInitializer 实现旨在捆绑在一个 JAR 文件中,该文件又被放入 webapp 的 /WEB-INF/lib 中。 JAR 文件本身应该有一个/META-INF/services/javax.servlet.ServletContainerInitializer 文件,其中包含JAR 中ServletContainerInitializer 实现的FQN。请注意,因此不应将此文件放在 webapp 本身中!

这允许 webapp 模块开发人员让他们的 JAR 文件挂钩 webapp 的启动和关闭周期。确实,他们也可以为此使用ServletContextListener@WebListener,但如果webapp 自己的web.xml 文件在metadata-complete="true" 中设置了metadata-complete="true" 属性&lt;web-app&gt; 这意味着webapp 应该'不扫描 JAR 中的注释(这样可以节省启动时间)。

ServletContainerInitializer您的特定情况中不起作用,这仅意味着您实际上并没有开发模块 JAR 文件,而只是您自己的 Web 应用程序不可或缺的一部分。在这种情况下,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.
    }

}

另见:

【讨论】:

  • 非常感谢,我似乎没有注意到 servletContainerInitializer “仅用于捆绑的 jars”的东西
  • 不客气。它与 JDBC 4.0 驱动程序中的概念相同。如果 JDBC 驱动程序 JAR 文件中有 /META-INF/services/java.sql.Driver 文件,则此类驱动程序可以自动注册,而无需 Class#forName()。另见docs.oracle.com/javase/7/docs/api/java/sql/DriverManager.html
  • ServletContainerInitializer 是否也适用于 ear lib 文件夹中的 jar?
  • @landal79:不,绝对不是。 EAR 库用于与 WAR 无关的完全不同的目的。 WAR 相关的库绝对不应该放在 EAR 库中,而应该放在 WAR 自己的 /WEB-INF/lib 中。
  • 至少在 Apache Tomcat 8.0.32 中,只要创建了适当的 META-INF/services/javax.servlet.ServletContainerInitializer,就可以为 Web 应用程序而不是其 JAR 注册 ServletContainerInitializers。要记住的另一件重要的事情是ServletContainerInitializers 在启动期间在ServletContextListeners 之前加载,因此如果您需要在捆绑在JAR 中的给定第三方ServletContainerInitializer 之前加载代码,唯一的选择似乎是实现@ 987654348@ 作为 Web 应用程序的一部分。
【解决方案2】:

检查您是否正确配置了 ServletContainerInitializer。 ServletContainerInitializer 类名应该在一个文件中配置:

META-INF/services/javax.servlet.ServletContainerInitializer

文件应该只包含类名。对于您的 Ex,它应该如下所示:

com.marmoush.javaexamples.nullhaus.servlet.MyInit

文件 (META-INF/services/javax.servlet.ServletContainerInitializer) 可以捆绑在 WEB-INF/lib 中的库 JAR 中。

这是任何解释的example

【讨论】:

  • 对我不起作用,我的文件夹结构是:/javaexamples/Webcontent/META-INF 和 /javaexamples/src/com/marmoush... 所以我创建了 services 文件夹,如你所说META-INF,但没有用,所以我去找你说的链接,发现他说 META-INF 与“com”文件夹平行,所以我创建了另一个 META-INF @ /javaexamples/src/META-INF 并没有也不行
  • META-INF/services/javax.servlet.ServletContainerInitializer 应该在 WEB-INF/lib 中捆绑的库中
  • @IsmailMarmoush 您应该检查生成的 WAR 中的文件夹结构,而不是您的开发文件夹结构,那里应该有 WEB-INF/classes/META-INF/services/javax.servlet.ServletContainerInitializer,我可以确认它适用于在 Apache 中注册 ServletContainerInitializer雄猫 8.0.32.
猜你喜欢
  • 2018-09-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多