这里的SpringMvc是基于注解版的, 在Servlet3.0之后注解版为主要的实现方式。

public class AppStarter implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
// Ioc 容器
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.register(SpringMVCConfig.class);

// IOC未启动
// 配置DispatchServlet: FrameworkServlet: initServletBean()
DispatcherServlet servlet = new DispatcherServlet(context);
// servlet加入到servletContext后,Tomcat会对DispatcherServlet初始化
ServletRegistration.Dynamic registration = servletContext.addServlet("servlet", servlet);
registration.setLoadOnStartup(1);
registration.addMapping("/");

}
}


文章目录

1.Spi机制处理

SpringMvc 源码分析 (SpringMvc 启动流程和原理解析) (二)_spring
SpringMvc 源码分析 (SpringMvc 启动流程和原理解析) (二)_初始化_02
Servlet的规范ServletContainerInitializer的实现类​​​SpringServletContainerInitializer​​​上面的注解​​@HandlesTypes​​​代表着​​WebApplicationInitializer​​这个接口的实现都是来自Spi机制的。

SpringMvc 源码分析 (SpringMvc 启动流程和原理解析) (二)_初始化_03
于是加载了所有实现WebApplicationInitializer的接口的类

SpringMvc 源码分析 (SpringMvc 启动流程和原理解析) (二)_spring_04

2.调用onStarterup方法

于是找到了AppStarter这个主类, 调用WebApplicationInitializer的onStartup方法。

SpringMvc 源码分析 (SpringMvc 启动流程和原理解析) (二)_tomcat_05
这个方法:

  1. 实例化一个ioc容器, 但是只是一个空的容器
  2. 实例化DispatcherServlet, 并在其中传入ioc容器, 并注册到了ServletContext中, 就是注册到了Tomcat中

这里因为DipatcherServlet是一个Servlet, 所以会遵循Servlet规范:

  1. Servlet 创建对象
  2. Servlet 调用init初始化
  3. 每次请求调用service方法进行处理
  4. tomcat停止的时候调用destroy方法

SpringMvc 源码分析 (SpringMvc 启动流程和原理解析) (二)_初始化_06

3.DispatcherServlet类分析

SpringMvc 源码分析 (SpringMvc 启动流程和原理解析) (二)_tomcat_07

SpringMvc 源码分析 (SpringMvc 启动流程和原理解析) (二)_tomcat_08
根据DispatcherServlet -> FrameworkServlet -> HttpServletBean -> HttpServlet -> GenericServlet -> Servlet

SpringMvc 源码分析 (SpringMvc 启动流程和原理解析) (二)_spring_09

这里的HttpServlet -> GenericServlet -> Servlet 为Servlet包下的
DispatcherServlet -> FrameworkServlet -> HttpServletBean 是Spring包下的

Servlet.service()
-> GenericService.service()
-> HttpServlet.service():doGet/Post
-> HttpServletBean
-> FrameworkServlet.processRequest(): 统一处理请求的入口
-> DispatcherServlet.doService()
下一篇进行介绍

HttpServletBean 会有一个强大的init方法:
SpringMvc 源码分析 (SpringMvc 启动流程和原理解析) (二)_tomcat_10
这里的initServletBean为模板方法模式, 为子类提供扩展

FrameworkServlet#initServletBean()
SpringMvc 源码分析 (SpringMvc 启动流程和原理解析) (二)_java_11

initFrameworkServlet为模板方法模式, 为子类提供扩展

4.web容器的准备阶段

SpringMvc 源码分析 (SpringMvc 启动流程和原理解析) (二)_spring_12

protected WebApplicationContext initWebApplicationContext() {
WebApplicationContext rootContext =
WebApplicationContextUtils.getWebApplicationContext(getServletContext());
WebApplicationContext wac = null;

if (this.webApplicationContext != null) {
// A context instance was injected at construction time -> use it
wac = this.webApplicationContext;
if (wac instanceof ConfigurableWebApplicationContext) {
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
if (!cwac.isActive()) {
// The context has not yet been refreshed -> provide services such as
// setting the parent context, setting the application context id, etc
if (cwac.getParent() == null) {
// The context instance was injected without an explicit parent -> set
// the root application context (if any; may be null) as the parent
cwac.setParent(rootContext);
}
configureAndRefreshWebApplicationContext(cwac);
}
}
}
if (wac == null) {
// No context instance was injected at construction time -> see if one
// has been registered in the servlet context. If one exists, it is assumed
// that the parent context (if any) has already been set and that the
// user has performed any initialization such as setting the context id
wac = findWebApplicationContext();
}
if (wac == null) {
// No context instance is defined for this servlet -> create a local one
wac = createWebApplicationContext(rootContext);
}

if (!this.refreshEventReceived) {
// Either the context is not a ConfigurableApplicationContext with refresh
// support or the context injected at construction time had already been
// refreshed -> trigger initial onRefresh manually here.
synchronized (this.onRefreshMonitor) {
onRefresh(wac);
}
}

if (this.publishContext) {
// Publish the context as a servlet context attribute.
String attrName = getServletContextAttributeName();
getServletContext().setAttribute(attrName, wac);
}

return wac;
}

这个方法中提供了​​父子容器​​​的概念。
这个方法中有​​​onRefresh​​​方法, 是spring提供的一个模板方法的扩展方法
SpringMvc 源码分析 (SpringMvc 启动流程和原理解析) (二)_java_13

这个onRefresh()方法提供了根据不同的策略来初始化容器中的组件

SpringMvc 源码分析 (SpringMvc 启动流程和原理解析) (二)_初始化_14

这里设计到了web容器的9大组件。下一篇进行介绍。

5.Question

1.ioc容器是什么时候初始化的

RA:
1.Tomcat启动的时候, 会创建每一个Servlet对象
2.Tomcat会给每一个DispatcherServlet创建对象
3.当DispatcherServlet初始化之后 ioc容器也会初始化

2.9大组件什么时候初始化的

RA:
利用的是Spring的事件驱动初始化的。
1.tomcat启动
2.触发DS初始化
3.初始化全部结束后, 容器会发送事件, 初始化9大组件

3.IOC容器和web容器是什么时候初始化的

RA:
IOC容器为tomcat启动后, 监听器钩子启动IOC容器, 实例化: 应用启动监听器回调。
web容器为tomcat调用DS的初始化init(), 进行初始化: DS初始化init()回调。