1、Tomcat(Servlet3.0规范的web容器)启动时,会查找ServletContainerInitializer接口实现类;
2、 Spring框架提供了一个SpringServletContainerInitializer类,实现了ServletContainerInitializer接口。
在这个类中的onStartup()方法,需要一个Set<Class<?>> webAppInitializerClasses类型的参数,也就是WebApplicationInitializer接口的实现类。
@HandlesTypes(WebApplicationInitializer.class)
public class SpringServletContainerInitializer implements ServletContainerInitializer {
@Override
public void onStartup(@Nullable Set<Class<?>> webAppInitializerClasses, ServletContext servletContext)
throws ServletException {
//WebApplicationInitializer接口的实现类集合
List<WebApplicationInitializer> initializers = new LinkedList<>();
if (webAppInitializerClasses != null) {
//遍历参数WebApplicationInitializer接口的实现类集合
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 {
//将当前对象加入到新创建的List集合
initializers.add((WebApplicationInitializer)
ReflectionUtils.accessibleConstructor(waiClass).newInstance());
}
catch (Throwable ex) {
//抛出容器初始化异常
throw new ServletException("Failed to instantiate WebApplicationInitializer class", ex);
}
}
}
}
//如果新创建的集合为空
if (initializers.isEmpty()) {
//输出日志:在类路径上未检测到spring webapplicationinitializer类型
servletContext.log("No Spring WebApplicationInitializer types detected on classpath");
return;
}
servletContext.log(initializers.size() + " Spring WebApplicationInitializers detected on classpath");
//排序
AnnotationAwareOrderComparator.sort(initializers);
//遍历List集合
for (WebApplicationInitializer initializer : initializers) {
//调用当前对象(我们写的配置类)的onStartup(),也就是我们写的配置类的onStartup(),进行初始化配置
initializer.onStartup(servletContext);
}
}
}
3、WebApplicationInitializer接口,又有抽象类实现它
public interface WebApplicationInitializer {
void onStartup(ServletContext servletContext) throws ServletException;
}
4、AbstractContextLoaderInitializer 实现了WebApplicationInitializer 接口
AbstractDispatcherServletInitializer类继承了AbstractContextLoaderInitializer
AbstractAnnotationConfigDispatcherServletInitializer继承了AbstractDispatcherServletInitializer
为了创建容器,我们就必须写WebApplicationInitializer接口真正的实现类DispatcherServletConfig;
//AbstractContextLoaderInitializer
public abstract class AbstractContextLoaderInitializer implements WebApplicationInitializer {
protected final Log logger = LogFactory.getLog(getClass());
//重写接口的方法onStartup()
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
registerContextLoaderListener(servletContext);
}
//注册监听器
protected void registerContextLoaderListener(ServletContext servletContext) {
WebApplicationContext rootAppContext = createRootApplicationContext();
if (rootAppContext != null) {
ContextLoaderListener listener = new ContextLoaderListener(rootAppContext);
listener.setContextInitializers(getRootApplicationContextInitializers());
servletContext.addListener(listener);
}
else {
logger.debug("No ContextLoaderListener registered, as " +
"createRootApplicationContext() did not return an application context");
}
}
@Nullable
protected abstract WebApplicationContext createRootApplicationContext();
@Nullable
protected ApplicationContextInitializer<?>[] getRootApplicationContextInitializers() {
return null;
}
}
5.AbstractDispatcherServletInitializer
public abstract class AbstractDispatcherServletInitializer extends AbstractContextLoaderInitializer {
public static final String DEFAULT_SERVLET_NAME = "dispatcher";
//重写onStartup()
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
//调用父类onStartup()方法
super.onStartup(servletContext);
//注册DispatcherServlet(SpringMVC核心控制器)
registerDispatcherServlet(servletContext);
}
//注册DispatcherServlet(SpringMVC核心控制器)
protected void registerDispatcherServlet(ServletContext servletContext) {
String servletName = getServletName();
Assert.hasLength(servletName, "getServletName() must not return null or empty");
WebApplicationContext servletAppContext = createServletApplicationContext();
Assert.notNull(servletAppContext, "createServletApplicationContext() must not return null");
FrameworkServlet dispatcherServlet = createDispatcherServlet(servletAppContext);
Assert.notNull(dispatcherServlet, "createDispatcherServlet(WebApplicationContext) must not return null");
dispatcherServlet.setContextInitializers(getServletApplicationContextInitializers());
//向容器中添加DispatcherServlet
ServletRegistration.Dynamic registration = servletContext.addServlet(servletName, dispatcherServlet);
if (registration == null) {
throw new IllegalStateException("Failed to register servlet with name '" + servletName + "'. " +
"Check if there is another servlet registered under the same name.");
}
//设置加载级别
registration.setLoadOnStartup(1);
//加载Mapping映射
registration.addMapping(getServletMappings());
//设置异步请求
registration.setAsyncSupported(isAsyncSupported());
//获取过滤器
Filter[] filters = getServletFilters();
if (!ObjectUtils.isEmpty(filters)) {
for (Filter filter : filters) {
//注册过滤器
registerServletFilter(servletContext, filter);
}
}
customizeRegistration(registration);
}
6、AbstractAnnotationConfigDispatcherServletInitializer
public abstract class AbstractAnnotationConfigDispatcherServletInitializer
extends AbstractDispatcherServletInitializer {
@Override
@Nullable
//加载Spring容器:Root WebApplicationContext(Spring)
protected WebApplicationContext createRootApplicationContext() {
//获取子类的对象数组
Class<?>[] configClasses = getRootConfigClasses();
if (!ObjectUtils.isEmpty(configClasses)) { //如果通过ObjectUtils查到的configClasses不为空
//创建AnnotationConfigWebApplicationContext容器
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
//将数组注册至容器
context.register(configClasses);
//返回容器
return context;
}
else {
return null;
}
}
// 加载Spring容器:Serlvet WebApplicationContext(Spring MVC)
@Override
protected WebApplicationContext createServletApplicationContext() {
//创建容器
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
//获取子类的对象数组
Class<?>[] configClasses = getServletConfigClasses();
if (!ObjectUtils.isEmpty(configClasses)) { //如果通过ObjectUtils查到的configClasses不为空
context.register(configClasses);//将数组注册至容器
}
return context; //返回容器
}
@Nullable
protected abstract Class<?>[] getRootConfigClasses();
@Nullable
protected abstract Class<?>[] getServletConfigClasses();
}
7、在我们自己写的DispatcherServletConfig就必须重写三个方法
和onStartup()方法,加载监听器和过滤器
// 加载Spring容器:Root WebApplicationContext(Spring)
//AppRootConfig该类对Serlvet Root WebApplicationContext容器配置
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] {AppRootConfig.class};
}
// 加载Spring容器:Serlvet WebApplicationContext(Spring MVC)
//SpringMvcConfig该类对Serlvet WebApplicationContext容器配置
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[] {SpringMvcConfig.class};
}
// 设置DispatcherServlet映射路径为处理所有请求
@Override
protected String[] getServletMappings() {
return new String[] {"/"};
}