Spring MVC:Tomcat,Servlet,Spring

最近迷上了tomcat,小研究了下多层容器结构,下图来自互联网

Spring MVC相关的内容,一些基本的概念,转载几个讲解的部分内容学习一下

web容器中有servlet容器,spring项目部署后存在spring容器和springmvc容器。其中spring控制service层和dao层的bean对象。springmvc容器控制controller层bean对象。servlet容器控制servlet对象。项目启动是,首先 servlet初始化,初始化过程中通过web.xml中spring的配置加载spring配置,初始化spring容器和springmvc容器。待容器加载完成。servlet初始化完成,则完成启动。
HTTP请求到达web容器后,会到达Servlet容器,容器通过分发器分发到具体的spring的Controller层。执行业务操作后返回结果。

转自:Tomcat容器,Servlet容器,Spring容器的包含关系

在使用springmvc框架,会在web.xml文件配置一个DispatcherServlet,这正是web容器开始初始化,同时会在建立自己的上下文来持有SpringMVC的bean对象。
先从DispatcherServlet入手,从名字来看,它是一个Servlet。它的定义如下:

public class DispatcherServlet extends FrameworkServlet {

它是继承FrameworkServlet,来看一下整个的继承关系

从继承关系来看,DispatcherServlet继承FrameworkServlet和HttpServletBean而继承HttpServlet,通过使用Servlet API 来对HTTP请求进行响应,成为SpringMVC的前端处理器

时序图

注:作为Servlet,DispatcherServlet的启动和Servlet的启动相关联的。在Servlet初始化过程中,Servlet的init方法会被调用,以进行初始化,然而DispatcherServlet的基类,所以从HttpServletBean中的初始化过程开始。

DispatcherServlet的工作分为2部分,一部分是初始化(也就是图的上半部分),有initServletBean()启动,通过initWebApplicationContext()方法最终调用DispatcherServlet中的initStrategies()方法。另一部分(也就是图的下半部分),是对HTTP请求进行响应,作为Servlet,Web容器会调用Servlet的doGet()和doPost()方法,在经过FrameworkServlet的processRequest()简单处理后,会调用DispatcherServlet的doService方法,在这个方法调用中封装了doDispatch(),继续调用processDispatchResult方法返回调用信息

转自:SpringMVC源码解析-DispatcherServlet启动流程和初始化

在初始化完成时,所有的handlerMapping都已经被加载,handlerMapping存储着HTTP请求对应的映射数据,每一个handlerMapping持有从URL请求到Controller的映射

这里以SimpleUrlHandlerMapping为例来分析它的设计与实现。在SimpleUrlHandlerMapping中,定义了一个map来维持映射关系,即URL请求和控制器对应关系,
是SpringMVC应用可以根据HTTP请求确定对一个对应的Controller,具体来说,这些映射关系是通过接口类HandlerMapping来封装,在HandlerMapping接口中定义了一个getHandler方法,
通过这个方法,可以获得与HTTP请求对应的HandlerExecutionChain,在这个HandlerExecutionChain中,封装具体的Controller对象

时序图

转自:SpringMVC源码解析-HTTP请求处理和分发

Servlet源码:

可以看见servlet就是一个接口;接口就是规定了一些规范,使得一些具有某些共性的类都能实现这个接口,从而都遵循某些规范。
有的人往往以为就是servlet直接处理客户端的http请求,其实并不是这样,servlet并不会去监听8080端口;直接与客户端打交道是“容器”,比如常用的tomcat。
客户端的请求直接打到tomcat,它监听端口,请求过来后,根据url等信息,确定要将请求交给哪个servlet去处理,然后调用那个servlet的service方法,service方法返回一个response对象,tomcat再把这个response返回给客户端。

1. Servlet的生命周期

从创建到毁灭:

(1)调用 init() 方法初始化
(2)调用 service() 方法来处理客户端的请求
(3)调用 destroy() 方法释放资源,标记自身为可回收
(4)被垃圾回收器回收

由上面可以看见,servlet的init方法和destroy方法,一般容器调用这两个方法之间的过程,就叫做servlet的生命周期。
调用的整个过程就如上图所示。
当请求来容器第一次调用某个servlet时,需要先初始化init(),
但当某个请求再次打到给servlet时,容器会起多个线程同时访问一个servlet的service()方法。

由此可以看出,多个客户访问同一service()方法,会涉及线程安全的问题

(1)如果service()方法没有访问Servlet的成员变量也没有访问全局的资源比如静态变量、文件、数据库连接等,而是只使用了当前线程自己的资源,比如非指向全局资源的临时变量、request和response对象等。该方法本身就是线程安全的,不必进行任何的同步控制。
(2)如果service()方法访问了Servlet的成员变量,但是对该变量的操作是只读操作,该方法本身就是线程安全的,不必进行任何的同步控制。
(3)如果service()方法访问了Servlet的成员变量,并且对该变量的操作既有读又有写,通常需要加上同步控制语句。
(4)如果service()方法访问了全局的静态变量,如果同一时刻系统中也可能有其它线程访问该静态变量,如果既有读也有写的操作,通常需要加上同步控制语句。
(5)如果service()方法访问了全局的资源,比如文件、数据库连接等,通常需要加上同步控制语句。

面试问题:Servlet如何同时处理多个请求访问?
单实例多线程: 主要是请求来时,会由线程调度者从线程池李取出来一个线程,来作为响应线程。这个线程可能是已经实例化的,也可能是新创建的。

Servlet容器默认是采用单实例多线程的方式处理多个请求的:
1.当web服务器启动的时候(或客户端发送请求到服务器时),Servlet就被加载并实例化(只存在一个Servlet实例);
2.容器初始化化Servlet主要就是读取配置文件(例如tomcat,可以通过servlet.xml的设置线程池中线程数目,初始化线程池通过web.xml,初始化每个参数值等等。
3.当请求到达时,Servlet容器通过调度线程(Dispatchaer Thread) 调度它管理下线程池中等待执行的线程(Worker Thread)给请求者;
4.线程执行Servlet的service方法;
5.请求结束,放回线程池,等待被调用;
(注意:避免使用实例变量(成员变量),因为如果存在成员变量,可能发生多线程同时访问该资源时,都来操作它,照成数据的不一致,因此产生线程安全问题)

从上面可以看出:
第一:Servlet单实例,减少了产生servlet的开销;
第二:通过线程池来响应多个请求,提高了请求的响应时间;
第三:Servlet容器并不关心到达的Servlet请求访问的是否是同一个Servlet还是另一个Servlet,直接分配给它一个新的线程;如果是同一个Servlet的多个请求,那么Servlet的service方法将在多线程中并发的执行;
第四:每一个请求由ServletRequest对象来接受请求,由ServletResponse对象来响应该请求;

2. Spring

任何Spring Web的entry point,都是servlet。

大名顶顶的spring框架已经风靡多时,一个事物的出现和流行都是会有原因的,那么为什么spring 框架会出现呢?原因就是为了简化java开发。
spring的核心就是通过依赖注入、面向切面编程aop、和模版技术,解耦业务与系统服务,消除重复代码。借助aop,可以将遍布应用的关注点(如事物和安全)从它们的应用对象中解耦出来。

Spring MVC

Spring MVC的运行流程:

图:

转自:Servlet/Tomcat/ Spring 之间的关系

最后一部分是Tomcat的整体结构

连接器

多层容器结构

  • Engine:表示一个虚拟主机的引擎,一个 Tomcat Server 只有一个 引擎,连接器所有的请求都交给引擎处理,而引擎则会交给相应的虚拟主机去处理请求;
  • Host:表示虚拟主机,一个容器可以有多个虚拟主机,每个主机都有对应的域名,在 Tomcat 中,一个 webapps 就代表一个虚拟主机,当然 webapps 可以配置多个;
  • Context:表示一个应用容器,一个虚拟主机可以拥有多个应用,webapps 中每个目录都代表一个 Context,每个应用可以配置多个 Servlet。

定位servlet的流程图

转自:聊聊Tomcat的架构设计

发表评论