繁体   English   中英

Tomcat 如何在没有 web.xml 的情况下准确引导应用程序?

[英]How does Tomcat exactly bootstrap the app without web.xml?

我想知道Tomcat如何在 Spring MVC 上引导我的应用程序?

我有一个初始化程序:

public class AppInitializer implements WebApplicationInitializer {
    @Override
    public void onStartup(ServletContext container) {
        AnnotationConfigWebApplicationContext rootCtx = new AnnotationConfigWebApplicationContext();
        rootCtx.register(AppConfig.class);
        container.addListener(new ContextLoaderListener(rootCtx));
        AnnotationConfigWebApplicationContext dispatcherCtx = new AnnotationConfigWebApplicationContext();
        dispatcherCtx.register(FreeMarkerWebConfig.class);
        ServletRegistration.Dynamic dispatcher = container.addServlet("dispatcher", new DispatcherServlet(dispatcherCtx));
        dispatcher.setLoadOnStartup(1);
        dispatcher.addMapping("/");
    }
}

我知道为什么我们需要web.xml以及Tomcat如何使用它来引导应用程序。 但是我不明白如果没有xml文件而只有AppAppInitializerTomcat如何知道它应该使用哪个 servlet 来引导应用程序?

依赖关系

<!-- spring mvc -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>4.2.1.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context-support</artifactId>
    <version>4.2.1.RELEASE</version>
</dependency>
<!-- servlet -->
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>3.0.1</version>
</dependency>

...

我在 Spring 核心SpringServletContainerInitializer找到了这个类。 Tomcat使用它来引导我的应用程序是否正确?

http://docs.oracle.com/javaee/7/api/javax/servlet/ServletContainerInitializer.html?is-external=true

Servlet 3.0 添加了可插拔机制。 它的工作原理是,当您的应用程序加载时,Servlet 容器会扫描类路径以查找META-INF/services名为javax.servlet.ServletContainerInitializer的文件。 该文件的内容应该只是 Servlet 容器可以加载的初始化程序的实现名称。 你可以在spring-web jar 中看到这个文件。 它列出了org.springframework.web.SpringServletContainerInitializer作为初始化器的实现。

Spring 初始化器的工作原理是它通过 Servlet 容器传递WebApplicationInializer的所有实现(在类路径上)。 那么 Servlet 容器是如何知道传递这些实现的呢? 如果您查看初始化程序源代码,您将看到

@HandlesTypes(WebApplicationInitializer.class)
public class SpringServletContainerInitializer implements ServletContainerInitializer {

它是@HandlesType注释。 所有课程,并在上市甚至注释1 @HandlesTypes将获得由servlet容器拾起,并传递到SevletContainerInitializer通过一个回调方法参数

void onStartup(java.util.Set<java.lang.Class<?>> c, ServletContext ctx)

Set参数包含 Servlet 容器在扫描时获取的所有实现。 您可以查看源代码以了解 Spring 对这些实现做了什么。 它基本上只是调用onStartup所有inializers的,通过在ServletContext


1. 这听起来有点不清楚(并且上面的解释会在切线上有点偏离)所以我只是将它作为额外的贴在这里。 想象一下, @HandlesType

@HandlesTypes({WebApplicationInitializer.class, Controller.class})
public class SpringServletContainerInitializer implements ServletContainerInitializer {

这意味着 servlet 容器还将扫描用@Controller注释的类,并将这些类传递给 Spring 初始化程序的onStartup

这与一个事实有关,即 Servlet 3.0 API 在没有 web.xml 的情况下也能工作。 因此,它不是 Spring 功能。

更多信息: https : //blogs.oracle.com/swchan/entry/servlet_3_0_annotations

JSR 315:JavaTM Servlet 3.0 规范: https ://jcp.org/en/jsr/detail?id = 315

更新:

Spring WebApplicationInitializer 提供了一种编程方式来配置符合 Servlet 3.0+ 的 servlet 容器中的 Spring DispatcherServlet 和 ContextLoaderListener,而不是通过 web.xml 文件添加此配置。

答案是Servlet 3.0 规范中引入的ServletContainerInitializer 接口,该接口的实现者在上下文启动阶段得到通知,并且可以通过提供的ServletContext 执行任何程序注册。

Spring 通过 SpringServletContainerInitializer 类实现了 ServletContainerInitializer。 根据 Servlet 规范,此实现必须在库 jar 文件的 META-INF/services/javax.servlet.ServletContainerInitializer 文件中声明 - Spring 在 spring-web*.jar jar 文件中声明它并有一个条目org.springframework.web.SpringServletContainerInitializer

SpringServletContainerInitializer 类有一个 @HandlerTypes 注释,值为 WebApplicationInitializer,这意味着 Servlet 容器将扫描实现 WebApplicationInitializer 实现的类,并使用这些类调用 onStartUp 方法,这就是 WebApplicationInitializer 适合的地方。

有点令人费解,但好消息是所有这些细节都在 spring-web 框架内完全抽象出来,开发人员只需配置 WebApplicationInitializer 的实现并生活在 web.xml 自由世界中。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM