[英]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
文件而只有AppAppInitializer
, Tomcat
如何知道它应该使用哪个 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.