spring中的Web上下文(ServletContext),Spring上下文(WebApplicationContext),SpringMVC上下文

        Servlet规范定义了一个API标准,这一标准的实现通常称为Servlet容器,比如开源的Tomcat、JBoss。

        web容器更准确的说应该叫web服务器,它是来管理和部署 web应用的。web容器最典型的就是tomcat了,Tomcat是web容器也是servlet容器。所谓容器(服务器、中间件等),就是提供一些底层的、业务无关的基本功能,为真正的Servlet提供服务。

         简单来说:容器负责根据请求的信息找到对应的Servlet,传递Request和Response参数,调用Servlet的service方法,完成请求的响应。

ServletContext:

        javaee标准规定了,Servlet容器(如Tomcat)需要在Web应用项目启动时,给Web应用项目初始化一个全局的上下文环境,这个全局的上下文环境就是ServletContext,ServletContext实例包含了所有servlet共享的资源信息。ServletContext中的信息都是由容器提供的,通常是配置web.xml。

spring启动过程及上下文WebApplicationContext

  • 首先,对于一个web应用,其部署在web容器中,web容器提供其一个全局的上下文环境,这个上下文就是ServletContext,其为后面的spring IoC容器提供宿主环境;

  • 其次,在web.xml中会提供有ContextLoaderListener,如上图所示实现了ServletContextListener并继承了ContextLoader类。

        ServletContextListener是Java EE标准接口之一,类似tomcat,jetty的Web容器启动时便会触发该接口的contextInitialized(ServletContextEvent event)方法,通知说Web容器初始化正在进行,在停止的时候会触发该接口的contextDestroyed(ServletContextEvent event)方法,通知说ServletContext上下文即将关闭。具体看博文ServletContextListener

       ContextLoader是对根应用程序上下文执行实际的初始化工作,由ContextLoaderListener调用。具体看博文ContextLoader

       ContextLoaderListener像桥梁一样连接了容器启动与Spring上下文初始化。在web容器启动时,会触发容器初始化事件,此时ContextLoaderListener会监听到这个事件,其contextInitialized方法会被调用,在这个方法中,spring会初始化一个启动上下文,这个上下文被称为根上下文,即WebApplicationContext,这是一个接口,其实际的实现类是XmlWebApplicationContext,这个就是spring的IOC容器,其对应的Bean定义的配置由web.xml中的context-param标签指定。

        在这个IOC容器会加载配置文件中的bean定义,初始化完毕后,spring以WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE为属性Key,将其存储到ServletContext中,便于获取,如下图所示

      在tomcat启动时也打印出来了上面的信息

[DEBUG] 2019-11-09 03:18:58,899 [localhost-startStop-1] org.springframework.web.context.ContextLoader - Published root WebApplicationContext as ServletContext attribute with name [org.springframework.web.context.WebApplicationContext.ROOT]

        扩展:Sping自带了多种类型的上下文,XmlWebApplicationContext是其中的一个,是从Web应用下的一个或多个xml配置文件中加载上下文定义。

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

注意:该监听器,默认读取/WEB-INF/下的applicationContext.xml文件。但是通过context-param指定配置文件路径后,便会去你指定的路径下读取对应的配置文件,并进行初始化。 

    contextLoaderListener要加载应用中的其他bean,这些bean通常是驱动应用后端的中间层和数据层组件。

SpringMVC上下文

  • 再次,contextLoaderListener监听器初始化完毕后,开始初始化web.xml中配置的Servlet,这个servlet可以配置多个,以最常见的DispatcherServlet为例,这个servlet实际上是一个标准的前端控制器,用以转发、匹配、处理每个servlet请求。DispatcherServlet上下文在初始化的时候会建立自己的IOC上下文,用以持有spring mvc相关的bean。

<servlet>
	<servlet-name>springMvc</servlet-name>
	<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
	<init-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>classpath:spring-mvc.xml</param-value>
	</init-param>
</servlet>

        在建立DispatcherServlet自己的IOC上下文时,会利用WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE先从ServletContext中获取之前的根上下文(即WebApplicationContext)作为自己上下文的parent上下文。有了这个parent上下文之后,再初始化自己持有的上下文。这样在SpringMVC中的Controller这些bean就可以注入Spring容器中的bean。

   DispatcherServlet的初始化构造器如下

public DispatcherServlet(WebApplicationContext webApplicationContext) {
	super(webApplicationContext);
	setDispatchOptionsRequest(true);
}

       这个DispatcherServlet初始化自己上下文的工作在其initStrategies方法中可以看到,大概的工作就是初始化处理器映射、视图解析等。这个servlet自己持有的上下文默认实现类也是XmlWebApplicationContext。

/**
	 * 初始化此servlet使用的策略对象
	 * @param context
	 */
	protected void initStrategies(ApplicationContext context) {
		/**
		 * 初始化此类使用的MultipartResolver。 如果在BeanFactory中没有为此名称空间定义给定名称的bean,则不提供任何多部分处理。
		 * 我们通常会在我们的SpringMVC配置文件中对此Resolver进行配置
		 *
		 */
		initMultipartResolver(context);
		initLocaleResolver(context);
		initThemeResolver(context);
		/**
		 * 初始化此类使用的HandlerMappings。 如果BeanFactory中没有为此名称空间定义HandlerMapping
		 * Bean,则默认为BeanNameUrlHandlerMapping。
		 */
		initHandlerMappings(context);
		initHandlerAdapters(context);
		/**
		 * 初始化此类使用的HandlerExceptionResolver。
		 * 如果在BeanFactory中没有为该名称空间定义给定名称的bean,我们默认不使用任何异常解析器。
		 * 我们通常会在我们的SpringMVC配置文件中对此Resolver进行配置我们自定义的异常处理类来进行统一异常处理
		 */
		initHandlerExceptionResolvers(context);
		/**
		 * 初始化此servlet实例使用的RequestToViewNameTranslator。
		 * 如果未配置任何实现,则默认为DefaultRequestToViewNameTranslator。
		 */
		initRequestToViewNameTranslator(context);
		/**
		 * 初始化此类使用的ViewResolver。 如果在BeanFactory中没有为此名称空间定义ViewResolver
		 * bean,则默认为InternalResourceViewResolver。
		 * 我们通常会在我们的SpringMVC配置文件中配置我们的视图解析器的相关信息,如jsp,html
		 */
		initViewResolvers(context);
		initFlashMapManager(context);
	}

      初始化完毕后,spring以与servlet的名字相关(此处不是简单的以servlet名为Key,而是通过一些转换,具体可自行查看源码)的属性为属性Key,也将其存到ServletContext中,以便后续使用。

     同样在tomcat启动时也打印出了初始化SpringMVC的信息,如下

[DEBUG] 2019-11-09 03:19:03,245 [localhost-startStop-1] org.springframework.web.servlet.DispatcherServlet - Published WebApplicationContext of servlet 'springMvc' as ServletContext attribute with name [org.springframework.web.servlet.FrameworkServlet.CONTEXT.springMvc]

   从上面的初始化中也可以看到DispatcherServlet中主要是控制器、视图解析器、处理器映射这些Bean。

       这样每个servlet就持有自己的上下文,即拥有自己独立的bean空间,同时各个servlet共享相同的bean,即根上下文(第2步中初始化的上下文)定义的那些bean。

参考:spring中DispatcherServlet、WebApplicationContext、ServletContext之间的关系 

ContextLoaderListener做了哪些事

使用 Spring 的监听器 ContextLoaderListener(掌握)

【Spring】- IOC容器初始化过程

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值