⭐表示重要。

第一章:Servlet 生命周期回顾

Servlet的生命周期回顾.png

生命周期环节 调用的方法 时机 次数
创建对象 无参构造器 默认:第一次请求,可以修改为Web应用启动时 一次
初始化 init(ServletConfig servletConfig) 创建对象后 一次
处理请求 service(ServletRequest servletRequest, ServletResponse servletResponse) 接收到请求后 多次
清理操作 destroy() Web应用卸载之前 一次

第二章:初始化操作调用路线图

2.1 类和接口之间的关系

类和接口之间的关系.png

2.2 调用线路图

  • 调用线路图显示是方法调用的顺序,但是实际运行的时候本质上都是调用 DispatcherServlet 对象的方法。包括这里涉及到的接口的方法,也不是去调用接口中的『抽象方法』。毕竟抽象方法是没法执行的。抽象方法一定是在某个实现类中有具体实现才能被调用。
  • 而对于最终的实现类:DispatcherServlet 来说,所有父类的方法最后也都是在 DispatcherServlet 对象中被调用的。

调用线路图.png

第三章:IOC 容器的创建

  • 所在类:org.springframework.web.servlet.FrameworkServlet。
  1. public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware {
  2. ...
  3. protected WebApplicationContext createWebApplicationContext(@Nullable ApplicationContext parent) {
  4. Class<?> contextClass = getContextClass();
  5. if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
  6. throw new ApplicationContextException(
  7. "Fatal initialization error in servlet with name '" + getServletName() +
  8. "': custom WebApplicationContext class [" + contextClass.getName() +
  9. "] is not of type ConfigurableWebApplicationContext");
  10. }
  11. // 创建 IOC 容器
  12. ConfigurableWebApplicationContext wac =
  13. (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
  14. wac.setEnvironment(getEnvironment());
  15. // 设置父容器
  16. wac.setParent(parent);
  17. String configLocation = getContextConfigLocation();
  18. if (configLocation != null) {
  19. wac.setConfigLocation(configLocation);
  20. }
  21. configureAndRefreshWebApplicationContext(wac);
  22. return wac;
  23. }
  24. }

第四章:将 IOC 容器对象存入应用域

  • 所在类:org.springframework.web.servlet.FrameworkServlet
  1. public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware {
  2. ...
  3. protected WebApplicationContext initWebApplicationContext() {
  4. WebApplicationContext rootContext =
  5. WebApplicationContextUtils.getWebApplicationContext(getServletContext());
  6. WebApplicationContext wac = null;
  7. if (this.webApplicationContext != null) {
  8. // A context instance was injected at construction time -> use it
  9. wac = this.webApplicationContext;
  10. if (wac instanceof ConfigurableWebApplicationContext) {
  11. ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
  12. if (!cwac.isActive()) {
  13. // The context has not yet been refreshed -> provide services such as
  14. // setting the parent context, setting the application context id, etc
  15. if (cwac.getParent() == null) {
  16. // The context instance was injected without an explicit parent -> set
  17. // the root application context (if any; may be null) as the parent
  18. cwac.setParent(rootContext);
  19. }
  20. configureAndRefreshWebApplicationContext(cwac);
  21. }
  22. }
  23. }
  24. if (wac == null) {
  25. // 获取 IOC 容器
  26. wac = findWebApplicationContext();
  27. }
  28. if (wac == null) {
  29. // 创建 IOC 容器
  30. wac = createWebApplicationContext(rootContext);
  31. }
  32. if (!this.refreshEventReceived) {
  33. // Either the context is not a ConfigurableApplicationContext with refresh
  34. // support or the context injected at construction time had already been
  35. // refreshed -> trigger initial onRefresh manually here.
  36. synchronized (this.onRefreshMonitor) {
  37. onRefresh(wac);
  38. }
  39. }
  40. if (this.publishContext) {
  41. // 获取存入应用域时专用的属性名
  42. String attrName = getServletContextAttributeName();
  43. // 存入
  44. getServletContext().setAttribute(attrName, wac);
  45. }
  46. return wac;
  47. }
  48. }
  • 看到这一点的意义:SpringMVC 有一个工具方法,可以从应用域获取 IOC 容器对象的引用。
  • 工具类:org.springframework.web.context.support.WebApplicationContextUtils。
  • 工具方法:getWebApplicationContext()。
  1. public abstract class WebApplicationContextUtils {
  2. ...
  3. @Nullable
  4. public static WebApplicationContext getWebApplicationContext(ServletContext sc) {
  5. return getWebApplicationContext(sc, WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
  6. }
  7. }

第五章:请求映射初始化

  • FrameworkServlet.createWebApplicationContext() —> FrameworkServlet.configureAndRefreshWebApplicationContext() —> wac.refresh(); —> org.springframework.web.servlet.DispatcherServlet.initStrategies() —> org.springframework.web.servlet.DispatcherServlet.initHandlerMappings() 。

请求映射初始化.png

第六章:总结

  • 整个启动过程我们关心如下要点:
  • ① DispatcherServlet 本质上是一个 Servlet,所以天然的遵循 Servlet 的生命周期。所以宏观上是 Servlet 生命周期来进行调度。
  • ② DispatcherServlet 的父类是 FrameworkServlet。
    • FrameworkServlet 负责框架本身相关的创建和初始化。
    • DispatcherServlet 负责请求处理相关的初始化。
  • ③ FrameworkServlet 创建 IOC 容器对象之后会存入应用域。
  • ④ FrameworkServlet 完成初始化会调用 IOC 容器的刷新方法。
  • ⑤ 刷新方法完成触发刷新事件,在刷新事件的响应函数中,调用 DispatcherServlet 的初始化方法。
  • ⑥ 在 DispatcherServlet 的初始化方法中初始化了请求映射等。