[TOC]
Tomcat中部署spring web application
一、Servlet容器
java的web应用是基于Servlet的,Tomcat是比较有名的Servlet容器,一个Tomcat中可以部署多个Servlet。下图是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种方式可接收到这两个通知事件:
定义在web.xml配置文件中,也就是本文描述的方式;
加上javax.servlet.annotation.WebListener注解;
通过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()方法。
WebApplicationContext的默认实现是XmlWebApplicationContext(配置在spring-web包中的ContextLoader.properties文件中),可以通过指定contextClass参数指定WebApplicationContext的实现,当然一般不会这么做。
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的创建,这里没有全部列出,这些一般也是非常用的功能。
- 调用refresh()方法实际上是调用了AbstractApplicationContext的refresh()方法,里面就是标准的spring的ApplicationContext的启动流程,主要是BeanFactory的初始化以及相应的bean的加载与初始化,具体可参考我的另一篇文章《Spring Boot/Spring的启动过程分析》。
3. DispatchServlet
DispatchServlet是将HTTP请求分发至handlers或者controllers的中央分发器,提供了便利的映射和异常处理功能。下面列一下它的一些特性:
- 一个web应用可以配置多个DispatcherServlet,每个DispatcherServlet在自己的命名空间内运行,加载自己私有的包含了mapping的应用上下文。只有通过ContextLoaderListener加载的上下文是共享的。
- 通过HandlerMapping的实现类来实现请求request到相应的handler的映射,可覆盖默认实现,默认实现是
1
org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping
2
org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping
- 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
- 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框架的理解。