SpringMVC之ServletContainerInitializer和WebApplicationInitializer
首先项目需要放在web容器中启动。例如:tomcat,jetty
容器启动时先去加载META-INF/services/javax.servlet.ServletContainerInitializer文件下写的指定类。
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OpudzUUj-1644830105026)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20220214152134761.png)]](https://img-blog.csdnimg.cn/376e72e93d314a598fd5c64a1035a4a4.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAeWFuX3Bhbg==,size_20,color_FFFFFF,t_70,g_se,x_16)

ServletContainerInitializer基于服务提供者接口(SPI)概念,是web容器启动时提供给第三方组件的接口。是 Servlet 3.0 新增的一个接口。Servlet3.0的Web应用服务器中,服务器会查找实现类,执行实现类的onStartup方法用于配置Servlet容器例如注册Servlet、Filter或Listener,以取代通过web.xml配置注册。这样就利于开发内聚的web应用框架。
@Override
public void onStartup(@Nullable Set<Class<?>> webAppInitializerClasses, ServletContext servletContext)
throws ServletException {
List<WebApplicationInitializer> initializers = new LinkedList<>();
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 {
//实例化WebApplicationInitializer子类
initializers.add((WebApplicationInitializer)
ReflectionUtils.accessibleConstructor(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中实现了ServletContainerInitializer的onStartup方法。可以看到方法中有两个参数
public void onStartup(@Nullable Set<Class<?>> webAppInitializerClasses, ServletContext servletContext)
如果ServletContainerInitializer接口的实现类使用@HandlesTypes注解声明了感兴趣的类或接口, 那么这个感兴趣的类及其子类或接口的实现类就会被设置到Set<Class<?>> webAppInitializerClasses中
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jJkrcgjQ-1644830105028)(C:\Users\ASUS\AppData\Roaming\Typora\typora-user-images\image-20220214155251577.png)]](https://img-blog.csdnimg.cn/c6fef815f0ce49dda0bd587ccd0a7635.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAeWFuX3Bhbg==,size_20,color_FFFFFF,t_70,g_se,x_16)
因此,ServletContainerInitializer和WebApplicationInitializer的关系为:spring实现web服务器提供的类,实现类为SpringServletContainerInitializer,再通过把WebApplicationInitializer的实现类作为参数,从而进行实例化对spring容器的加载
WebApplicationInitializer相当于web.xml,可以在其实现类中注册Servlet、Filter或Listener等操作
在WebApplicationInitializer的子类中使用AbstractAnnotationConfigDispatcherServletInitializer来配置,它会i加载DispatcherServlet、ContextLoaderListener、根容器、IOC容器,真正实现不再需要使用web.xml

createServletApplicationContext:创建web的ioc容器,主要用于用于和该Servlet相关的一些组件,比如Controller、ViewResovler等;
createRootApplicationContext:创建根容器,整个Web应用程序需要共享的一些组件,比如DAO、数据库的ConnectionFactory等
DispatcherServlet:把ioc容器放入其属性中,这样这样我们只要得到Servlet就可以得到WebApplicationContext对象,并利用这个对象访问spring容器管理的bean。
ContextLoaderListener:把ioc容器放入其属性中