1、Web.xml 是Spring应用和Servlet联系的中介
Servlet容器启动后,Servlet容器会根据web.xml中的配置初始化Spring容器。
2、Servlet3.0奠定了SpringBoot 零xml配置的基础
在Servlet3.0容器初始化时会调用jar包META-INF/services/javax.servlet.ServletContainerInitializer中指定的类的实现,先看看ServletContainerInitializer接口:
public interface ServletContainerInitializer {
void onStartup(Set<Class<?>> c, ServletContext ctx) throws ServletException;
}
而作为Servlet3.0容器之一的Tomcat,当然就会调用SpringWeb jar包下的实现,如下。
再看看SpringWeb的类SpringServletContainerInitializer
@HandlesTypes(WebApplicationInitializer.class)
public class SpringServletContainerInitializer implements ServletContainerInitializer {
@Override
public void onStartup(Set<Class<?>> webAppInitializerClasses, ServletContext servletContext)
throws ServletException {
List<WebApplicationInitializer> initializers = new LinkedList<WebApplicationInitializer>();
if (webAppInitializerClasses != null) {
for (Class<?> waiClass : webAppInitializerClasses) {
// Be defensive: Some servlet containers provide us with invalid classes,
// no matter what @HandlesTypes says...
if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) &&
WebApplicationInitializer.class.isAssignableFrom(waiClass)) {
try {
initializers.add((WebApplicationInitializer) waiClass.newInstance());
}
catch (Throwable ex) {
throw new ServletException("Failed to instantiate WebApplicationInitializer class", ex);
}
}
}
}
if (initializers.isEmpty()) {
servletContext.log("No Spring WebApplicationInitializer types detected on classpath");
return;
}
servletContext.log(initializers.size() + " Spring WebApplicationInitializers detected on classpath");
AnnotationAwareOrderComparator.sort(initializers);
for (WebApplicationInitializer initializer : initializers) {
initializer.onStartup(servletContext);
}
}
SpringServletContainerInitializer的类添加了@HandlesTypes注解,在@HandlesTypes注解中可以指定的感兴趣的类(如WebApplicationInitializer.class),就可以在onStartup()通过方法参数传入感兴趣的类(如WebApplicationInitializer)的所有的实现类,而这些实现类可以理解为具体实现了web.xml的功能,当然也可以有其他的用途)。下图是WebApplicationInitializer的几个具体的实现类:
上图的3个实现类,由类名就可以猜测到和web.xml配置的几个组件ContextLoaderListener、DispatcherServlet相关,这几个组件就是由这3个实现类创建的。由此,一言以蔽之:javax.servlet.ServletContainerInitializer中的实现类替代了web.xml的作用!
最后,从全局看下调用过程如下:
Servlet3.0容器(Tomcat)
-> SpringServletContainerInitializer.onStartup()
->WebApplicationInitializer.onStartup()
->createRootApplicationContext(Spring容器)
而Tomcat又是具体如何启动SpringWeb项目的,请看《Tomcat源码阅读—如何启动SpringWeb项目》;
如果想了解ContextLoaderListener、DispatcherServlet这两个组件是如何加载的,请看另一篇文章:《Springmvc源码阅读-父子容器的加载》