Spring如何与Tomcat框架进行集成

一、前言

本节我们讲究如何利用Tomcat的ContextLoaderListener扩展接口来把Spring框架与Tomcat进行连接起来。

二、ContextLoaderListener扩展接口

ContextLoaderListener一般用来启动一个Spring容器或者框架的根容器,例如Webx框架的WebxContextLoaderListener就是继承该类,实现了webx框架到Tomcat容器的衔接点,而SpringMVC则通过在ContextLoaderListener启动一个IOC来管理bo类的bean,下面首先看下ContextLoaderListener的类图结构:

可知ContextLoaderListener的两个方法都是含有一个ServletContextEvent类型的参数。

那么这个ContextLoaderListener一般是怎么使用的那?ContextLoaderListener一般是按照下面的方式配置到web.xml里面:

如上代码,首先创建了一个ContextLoaderListener实例,该实例会创建一个XmlWebApplicationContext应用程序上下文,contextConfigLocation是要告诉ContextLoaderListener要把哪些Bean注入到XmlWebApplicationContext管理的BeanFactory。

这里首先有几个问题,比如配置的全局的contextConfigLocation属性是怎么在ContextLoaderListener中获取的?ContextLoaderListener与Tomcat是什么关系那?ContextLoaderListener是如何创建的XmlWebApplicationContext?

为了解开前两个问题,我们需要看下Tomcat(本文tomcat版本为 apache-tomcat-8.5.12)中的一些代码时序图

  • 在Tomcat中一个StandardContext代表者一个Web应用,时序图中步骤(2)(3)在Web应用启动过程中会调用mergeParameters方法解析web.xml配置的context-param参数,并把这些参数设置到ApplicationContext中,也就是说上面配置的contextConfigLocation参数和值也保存到了ApplicationContext中,需要注意的是这里的ApplicationContext不同于Spring框架中的ApplicationContext,这里的ApplicationContext是tomcat中的ApplicationContext ,它实现了 org.apache.catalina.servlet4preview.ServletContext,是一个ServletContext,这个ApplicationContext是应用级别的,每个应用维护着自己的一个ApplicationContext对象,用来保存应用级别的变量信息,其内部通过 privatefinalConcurrentMap<String,String>parameters=newConcurrentHashMap<>();保存应用级别的变量信息。
  • 时序图中步骤(4)(5)(6)是初始化所有在web.xml里面配置的ServletContextListener的实现类,并以ApplicationContext为构造函数参数创建一个ServletContextEvent 作为ServletContext事件(内部实际维护的是ApplicationContext的一个门面类ApplicationContextFacade),然后调用所有实现类的contextInitialized的方法并传递ServletContextEvent作为参数,至此解开了ContextLoaderListener与Tomcat的关系,也就是说在tomcat的每个应用启动过程中会调用ContextLoaderListener的contextInitialized方法并且传递的参数里面包含该应用级别的一个ApplicationContext对象,该对象里面包含了该应用的全局作用域的变量集合。

下面看下ContextLoaderListener的contextInitialized方法时序图,看是如何创建XmlWebApplicationContext并获取到了contextConfigLocation变量的值作为Spring容器加载Bean的数据源:

  • 如上时序图步骤(3)创建Spring应用程序上下文XmlWebApplicationContext
  • 如上时序图步骤(5)设置XmlWebApplicationContext的ServletContext为ApplicationContextFacade
  • 如上时序图步骤(6)(7)从ServletContext中获取contextConfigLocation变量的值,这里为WEB-INF/applicationContext.xml
  • 如上时序图步骤(8)设置XmlWebApplicationContext的配置文件为WEB-INF/applicationContext.xml,这意味着会从WEB-INF/applicationContext.xml中解析Bean注入到XmlWebApplicationContext管理的BeanFactory。
  • 如上时序图步骤(9)刷新XmlWebApplicationContext应用程序上下文
  • 如上时序图步骤(10)保存XmlWebApplicationContext到ServletContext,这样应用里面任何有ServletContext的地方就可以获取XmlWebApplicationContext,从而可以获取XmlWebApplicationContext管理的所有Bean。

三、 SpringMVC与Tomcat容器的衔接点

SpringMvc是目前使用非常频繁的框架,springmvc里面经常会使用两级级联容器,并且每层容器都各有用途,使用过SpringMVC的童鞋都知道,一般我们在web.xml里面会配置一个listener和一个dispatcher,其实这就配置了两个spring IOC容器,并且dispatcher容器的父容器就是listener的容器。一般在web.xml里面配置如下:

<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>WEB-INF/applicationContext.xml</param-value>
</context-param>
<servlet>
    <servlet-name>springmvc</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
</servlet>

其中ContextLoaderListener会创建一个XMLWebApplicationContext上下文来管理contextConfigLocation配置的xml里面的普通bean,这个上节已经讲过。

DispatcherServlet也会创建一个XMLWebApplicationContext默认管理web-info/springmvc-servlet.xml里面的Controller bean,下面看下创建的流程时序图:

如图在DispatcherServlet的初始化方法中首先从ServletContext的全局变量表里面获取ContextLoaderListener创建的XMLWebApplicationContext上下文,然后使用该context作为父上下文创建了SpringMVC的servlet的context容器,并且设置namespace为springmvc-servlet,这个在查找配置文件时候用到,最后会拼接为springmvc-servlet.xml,最后刷新SpringMVC的servlet的context上下文。

一般我们在listener创建的父容器里面配置bo类用来具体操作业务,在dispatcher子容器里面配的Controller类,然后Controller里面具体调用bo类来实现业务。

至此结合上节通过Tomcat启动过程中调用ContextLoaderListener的contextInitialized方法首先创建了父容器用来管理bo bean,然后使用DispatcherServlet创建了子容器用来管理Controller bean ,ContextLoaderListener让SpringMVC与Tomcat容器联系起来了。

四、参考

  • https://docs.spring.io/spring/docs/4.3.13.RELEASE/spring-framework-reference/html/beans.html
  • https://docs.spring.io/spring/docs/4.3.13.RELEASE/spring-framework-reference/html/beans.html#beans-factory-extension

原文发布于微信公众号 - Java后端技术栈(t-j20120622)

原文发表时间:2019-07-30

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券