如果没有web.xml,Tomcat如何正确地引导应用程序?

我想知道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来引导应用程序?

依赖

   org.springframework spring-webmvc 4.2.1.RELEASE   org.springframework spring-context-support 4.2.1.RELEASE    javax.servlet javax.servlet-api 3.0.1  ... 

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

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

Servlet 3.0增加了可插拔性机制。 它是如何工作的,当你的应用程序被加载时,它会在类路径中扫描META-INF/services名为javax.servlet.ServletContainerInitializer的文件。 在那里,实现者应该具有实现的名称,servlet容器可以在其中加载它。 你可以在spring-web jar中看到这个文件。 它列出了org.springframework.web.SpringServletContainerInitializer作为初始化程序的实现。

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

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

它是@HandlesType注释。 @HandlesTypes列出的所有类甚至注释1 @HandlesTypes将被servlet容器拾取并通过单个回调方法参数传递给SevletContainerInitializer

 void onStartup(java.util.Set> c, ServletContext ctx) 

Set参数包含servlet容器在扫描时拾取的所有实现。 您可以查看源代码以了解Spring对这些实现的作用。 它基本上只调用所有inializers的onStartup,传入ServletContext


1.这听起来有点不清楚(上面解释它在切线上会有点偏差)所以我只是在这里发布一个额外的。 想象一下, @HandlesType代替了

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

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

它与一个事实相关,即Servlet 3.0 API在没有web.xml的情况下工作。 所以,它不是Springfunction。

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

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

UPD:

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自由世界中。