1. ServletContainerInitializer为Servlet规范提供的接口
会通过SPI机制加载ServletContainerInitializer的实现类
规定的SPI路径为META-INF\services\javax.servlet.ServletContainerInitializer
里面的内容为该接口的实现类
2. 启动的时候,会执行这些初始化类的onStartup方法
3. 在实现类上添加@HandlesTypes(ILuckService.class)注解,在tomcat启动的时候
会自动将该接口对应的子类,实现类,子接口传递过来,作为onStartup的set参数传递过来
// 容器启动的时候,会将HandlesTypes指定的这个类下面的子类,实现类,子接口传递过来
@HandlesTypes(ILuckService.class)
public class LuckServletContainerInitializer implements ServletContainerInitializer {
@Override
public void onStartup(Set<Class<?>> set, ServletContext ctx) throws ServletException {
set.forEach(temp -> System.out.println(temp.getName()));
// 手动注册servlet
ServletRegistration.Dynamic sciServlet = ctx.addServlet("sciServlet", new SciServlet());
sciServlet.addMapping("/sci/servlet");
// 注册监听器
ctx.addListener(SciListener.class);
// 手动注册Filter
FilterRegistration.Dynamic sciFilter = ctx.addFilter("sciFilter", SciFilter.class);
sciFilter.addMappingForServletNames(EnumSet.of(DispatcherType.REQUEST), true, "sciServlet");
sciFilter.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), true, "/*");
}
}
4. 而对于Spring,它也提供了一个实现类
并且SPI文件在spring-web/META-INF/services/javax.servlet.ServletContainerInitializer
内容为org.springframework.web.SpringServletContainerInitializer
根据下面源码,知道AbstractDispatcherServletInitializer符合条件,并且会自动注入DispatchServlet
并且有三个抽象方法{
// 创建SpringMVC容器
protected WebApplicationContext createServletApplicationContext();
// 获取DispatchServlet的映射路径
protected String[] getServletMappings();
// 创建父容器
protected WebApplicationContext createRootApplicationContext();
},而对与这三个,我们用的不是很多,它还提供一个一个继承于AbstractDispatcherServletInitializer的类
// 它将父类再一步简化,不需要在创建context对象,而是直接给定配置类,自动创建容器
// 所以,使用SpringMVC零配置,使用AbstractAnnotationConfigDispatcherServletInitializer是最终方法
AbstractAnnotationConfigDispatcherServletInitializer{
protected Class<?>[] getRootConfigClasses();
protected Class<?>[] getServletConfigClasses();
protected String[] getServletMappings();
}
*/
@HandlesTypes(WebApplicationInitializer.class)
public class SpringServletContainerInitializer implements ServletContainerInitializer {
// webAppInitializerClasses: 扫描到WebApplicationInitializer的实现类
@Override
public void onStartup(@Nullable Set<Class<?>> webAppInitializerClasses, ServletContext servletContext) throws ServletException {
if (webAppInitializerClasses != null) {
initializers = new ArrayList<>(webAppInitializerClasses.size());
for (Class<?> waiClass : webAppInitializerClasses) {
// 排除接口和抽象类
if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) && WebApplicationInitializer.class.isAssignableFrom(waiClass)) {
// 实例化对象
initializers.add((WebApplicationInitializer)ReflectionUtils.accessibleConstructor(waiClass).newInstance());
}
}
}
AnnotationAwareOrderComparator.sort(initializers);
// 执行Spring提供的类对应的initializer方法
for (WebApplicationInitializer initializer : initializers) {
// 其中包含了AbstractDispatcherServletInitializer,会自动注册一个DispatchServlet
initializer.onStartup(servletContext);{
super.onStartup(servletContext);
registerDispatcherServlet(servletContext);{
String servletName = getServletName();
// 创建SpringMVC子容器
WebApplicationContext servletAppContext = createServletApplicationContext();
// 创建DispatchServlet
FrameworkServlet dispatcherServlet = createDispatcherServlet(servletAppContext);
// 设置servlet的配置,和xml中一样的效果
dispatcherServlet.setContextInitializers(getServletApplicationContextInitializers());
// 动态注册
ServletRegistration.Dynamic registration = servletContext.addServlet(servletName, dispatcherServlet);
registration.setLoadOnStartup(1);
registration.addMapping(getServletMappings());
// 设置是否支持异步
registration.setAsyncSupported(isAsyncSupported());
// 设置过滤器
Filter[] filters = getServletFilters();
if (!ObjectUtils.isEmpty(filters)) {
for (Filter filter : filters) {
registerServletFilter(servletContext, filter);
}
}
// 自定义配置
customizeRegistration(registration);
}
}
}
}
}