SpringMVC流程分析(一):从一行配置入手,搞懂web环境下Ioc容器的构建

2023年 7月 18日 56.7k 0

本系列文章皆在分析SpringMVC的核心组件和工作原理,让你从springmvc浩如烟海的代码中跳出来,以一种全局的视角来重新审视SpringMVC的工作原理SpringMVC

思考,输出,沉淀。用通俗的语言陈述技术,让自己和他人都有所收获。
作者:毅航😜

前言

随着 Spring BootSpring Cloud 在开发中的普及,极大的简化了web开发的上手难度。可能你已经忘记当年经典的 Servlet + Spring MVC 的组合,忘记了那个繁琐配置 web.xml 时代。

本文将从web.xml文件中的一行简单配置开始分析,从细节着手,重新来分析 Servlet 是怎么和 Spring MVC 进行集成并完成Spring 容器初始化工作的。

下图展示了本系列文章重点分析的组件信息,其中 ContextLoaderListener是本文分析的重点。

image.png

熟悉又陌生的配置文件

在使用Spring MVC之前,通常我们会在web.xml文件中配置一个叫做ContextLoaderListener的监听器,具体配置如下。


   org.springframework.web.
            context.ContextLoaderListener
 

SpringMVC作为web容器, 其核心本质就是对servlet 的封装和处理, 所以必定需要一个servlet容器,自然而然就想到了其的使用肯定需要借助于Tomcat的帮助。

Tomcat的基本工作流程为,加载web.xml,解析其中内容,而其中配置有Spring,SpringMVC的配置文件信息,所以我们选择ContextLoaderListener作为入口,来探究和分析SpringMVC的启动流程。

在开始之前,我们不妨先思考一个问题,那这个监听器择ContextLoaderListener具体有什么作用呢?接下来,我们将带着这个问题来重新审视ContextLoaderListener这个组件。

监听器

监听器(Listener)是Servlet体系下的一个组件,其主要可用于监听和响应Web应用程序中事件的组件。它可以监听ServletSession、请求、上下文等不同级别的事件,并在事件发生时执行相应的逻辑。而组件ServletContextListener定义了方法contextInitializedcontextDestroyed分别用来监听ServletContext的创建和销毁。

回到我们之前讨论的ContextLoaderListener,其有如下的继承体系结构。

image.png

具体来看,ContextLoaderListener实现了javax.servlet.ServletContextListener接口,这保证了其可用于监听ServletContext的生命周期事件。

其外,由于ContextLoaderSpring中的一个辅助类,它用于在Web应用程序启动时加载Spring的应用上下文信息。它主要用于创建和初始化Spring的根应用上下文,以及将其关联到ServletContext中,使得在整个Web应用程序中可以共享和重用SpringBean

至此,我们可以大致明白SpringMVC一定程度上可以正常工作,其主要通过事件监听的模式来实现,而监听器正常工作,通常需要几大关键信息:即被监听对象,事件,监听器。 此时,ContextLoaderListener就相当于一个监听器,被监听的对象则是ServletContext,而事件则是Tomcat容器启动。

对于ContextLoaderListener的类结构信息,我们需要强调的是:

  • ServletContext对象是Tomcat
  • ServletContextListenerTomcat提供的接口
  • ContextLoaderListener则是Spring写的,并实现了ServletContextListener

Web环境中Ioc容器的构建

由于ContextLoaderListner实现了ServletContextListener接口,所以当Tomcat中的ServletContext创建时,便会触发一个创建ServletContextEvent事件,此时ContextLoaderListener便会监听到该事件,从而执行其中的contextInitialized(),而这个方法内部的initWebApplicationContext()就是用来初始化SpringIOC容器的。


public class ContextLoaderListener 
       extends ContextLoader implements ServletContextListener {

   /**
    * 初始化web容器
    */
   @Override
   public void contextInitialized(ServletContextEvent event) {
      initWebApplicationContext(event.getServletContext());
   }

其中方法initWebApplicationContext的逻辑如下

public WebApplicationContext initWebApplicationContext(ServletContext 
                                                         servletContext) {
       // ... 省略异常捕获,条件判断
      if (this.context == null) {
          // 创建一个web容器
         this.context = createWebApplicationContext(servletContext);
      }
      // ... 省略异常捕获,条件判断
      // 加载配置文件中context-param信息,刷新spring容器
      configureAndRefreshWebApplicationContext(cwac, servletContext);
   
      return this.context;
  }

在上述代码中,我们剔除掉了大量无关代码,不难发现initWebApplicationContext主要做了两件事:

  • 创建一个web容器
  • 加载spring配置文件,完成容器刷新工作

经过这一套流程处理下来,SpringIOC容器也就初始化完成,同时还会构建一个Web环境的容器WebApplicationContext容器信息。

总结

ContextLoaderListener的作用是监听Web应用程序的启动和销毁事件,同时在Web容器启动时从web.xml中获取Spring的相关配置文件,完成bean的初始化。

其实ContextLoaderListener更像一个桥梁,保证了SpringSpringMVC之间的整合。事实上,如果仅使用SpringMVC,而不使用Spring的其他功能(例如SpringIoC容器和Bean管理等),则在配置文件中配置ContextLoaderListener是可选的。

例如,如果仅创建Controller来处理请求和渲染视图,通常不需要显式配置ContextLoaderListener。因为DispatcherServlet自动创建一个子级的容器,并管理与SpringMVC相关的组件信息,如控制器、拦截器等。

相关文章

JavaScript2024新功能:Object.groupBy、正则表达式v标志
PHP trim 函数对多字节字符的使用和限制
新函数 json_validate() 、randomizer 类扩展…20 个PHP 8.3 新特性全面解析
使用HTMX为WordPress增效:如何在不使用复杂框架的情况下增强平台功能
为React 19做准备:WordPress 6.6用户指南
如何删除WordPress中的所有评论

发布评论