0%

Tomcat中部署spring web application

[TOC]

Tomcat中部署spring web application

一、Servlet容器

java的web应用是基于Servlet的,Tomcat是比较有名的Servlet容器,一个Tomcat中可以部署多个Servlet。下图是Tomcat的容器模型。

图 1 . Tomcat 容器模型

有关Servlet与Tomcat的原理推荐阅读下面几篇文章进行了解:

https://www.ibm.com/developerworks/cn/java/j-lo-servlet/index.html

https://www.ibm.com/developerworks/cn/java/j-lo-tomcat1/index.html

https://www.ibm.com/developerworks/cn/java/j-lo-tomcat2/

http://objcoding.com/2019/05/30/tomcat-architecture/

1. Tomcat中war的部署

web应用以war包的形式部署在Tomcat中,web.xml是web应用的部署配置文件,下面说说其中的一些配置元素。

元素 功能
servlet 指定servlet
servlet-mapping 指定servlet与url之间的映射关系
filter 指定filter
filter-mapping 指定filter与url之间的映射关系
listener 指定监听器监听servlet上下文事件
context-param servlet上下文初始化参数
welcome-file-list 一般用于指定欢迎页,如index.jsp

以上是对servlet容器的简单介绍,以及在Tomcat中以war部署web应用时,web.xml的作用。

二、Tomcat中启动spring

在Tomcat中启动spring也就意味着如何启动并初始化spring上下文,在web应用中该上下文就是WebApplicationContext。

1. ContextLoadListener

WebApplicationContext可以通过在web.xml中配置ContextLoadListener这个listener实现初始化。

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

ContextLoaderListener实现了ServletContextListener,该接口定义了两个方法可监听servlet的初始化与销毁,该接口的实现类也就是ContextLoaderListener有3种方式可接收到这两个通知事件:

  1. 定义在web.xml配置文件中,也就是本文描述的方式;

  2. 加上javax.servlet.annotation.WebListener注解;

  3. 通过ServletContext的addListener方法添加;

ContextLoaderListener在配置时需要注意:如果使用了org.springframework.web.util.Log4jConfigListener,需要在web.xml中将该listener配置在其之后。Log4jConfigListener用于初始化定制化的log4j。

2. WebApplicationContext的创建

ContextLoaderListener将具体的创建WebApplicationContext的操作委派给ContextLoader执行,其关键方法是

1
public WebApplicationContext initWebApplicationContext(ServletContext servletContext)

initWebApplicationContext先创建一个WebApplicationContext,然后完成配置并调用refresh()方法。

  1. WebApplicationContext的默认实现是XmlWebApplicationContext(配置在spring-web包中的ContextLoader.properties文件中),可以通过指定contextClass参数指定WebApplicationContext的实现,当然一般不会这么做。

  2. WebApplicationContext初始化的配置文件地址可以通过在web.xml文件中的context-param配置节中配置contextConfigLocation参数指定,如:

1
<context-param>
2
		<param-name>contextConfigLocation</param-name>
3
		<param-value>
4
			classpath*:config/spring/local/appcontext-*.xml,
5
			classpath*:config/spring/appcontext-*.xml
6
		</param-value>
7
</context-param>

​ PS:存在多个配置文件地址的情况下,后面文件中定义的的bean definition会覆盖前面的。

还有一些其他的可配置参数可以影响WebApplicationContext的创建,这里没有全部列出,这些一般也是非常用的功能。

  1. 调用refresh()方法实际上是调用了AbstractApplicationContext的refresh()方法,里面就是标准的spring的ApplicationContext的启动流程,主要是BeanFactory的初始化以及相应的bean的加载与初始化,具体可参考我的另一篇文章《Spring Boot/Spring的启动过程分析》。

3. DispatchServlet

DispatchServlet是将HTTP请求分发至handlers或者controllers的中央分发器,提供了便利的映射和异常处理功能。下面列一下它的一些特性:

  1. 一个web应用可以配置多个DispatcherServlet,每个DispatcherServlet在自己的命名空间内运行,加载自己私有的包含了mapping的应用上下文。只有通过ContextLoaderListener加载的上下文是共享的。
  2. 通过HandlerMapping的实现类来实现请求request到相应的handler的映射,可覆盖默认实现,默认实现是
    1
    org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping
    2
    org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping
  3. HandlerAdapter接口,用来适配请求和handler,可覆盖默认实现,默认实现是
    1
    org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter对应org.springframework.web.HttpRequestHandler
    2
    3
    org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter对应org.springframework.web.servlet.mvc.Controller
    4
    另外还有一个默认的
    5
    org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter
  4. HandlerExceptionResolver负责dispatcher的异常处理策略,例如,发生某些特定异常时映射到某个错误页面。
    这里只列出一些基础的,还有一些关于ViewResolver,MultipartResolver,LocaleResolver,ThemeResolver的没有列出,感兴趣的可以研究一下。

DispatchServlet的创建

DispatchServlet继承了FrameworkServlet,FrameworkServlet继承了HttpServletBean,HttpServletBean继承了HttpServlet。
servlet容器启动的时候会调用HttpServlet的init()方法,也就是说会调用HttpServletBean的init()方法,其中会调用FrameworkServlet的initServletBean()方法,其中会调用它的initWebApplicationContext()方法,创建这个DispatchServlet的ApplicationContext,并且会将ContextLoaderListener加载的ApplicationContext作为其parent。

那么如何才能让servlet容器去创建一个DispatchServlet呢?答案就是在web.xml中进行配置,示例如下:

1
<servlet>
2
        <servlet-name>springmvc</servlet-name>
3
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
4
        <init-param>
5
            <param-name>contextConfigLocation</param-name>
6
            <param-value>classpath:config/spring.mvc/appcontext-servlet.xml</param-value>
7
        </init-param>
8
        <load-on-startup>1</load-on-startup>
9
    </servlet>

其中contextConfigLocation参数指定这个DispatcherServlet的ApplicationContext的配置,<load-on-startup>1</load-on-startup>表示在容器启动时就加载。

好了,再往下就是spring mvc的内容了,还有待研究。

小结

本文基于对spring 3.2.5版本的源码阅读,目前spring最新版本已到5.2.x,内容上可能有些过时,但理论上不影响对spring框架的理解。