在日常调试项目时,总是利用tomcat去启动项目,并进行前后端联调,但对于前后端的请求响应的交互原理及过程并不是特别清晰。 为什么在前端发出相应请求,就能跳转到后端通过程序得到结果再响应到前端页面呢?! 为了加深对该过程的理解,故以tomcat为例,撰写此文。

在日常调试项目时,总是利用tomcat去启动项目,并进行前后端联调,但对于前后端的请求响应的交互原理及过程并不是特别清晰。

为什么在前端发出相应请求,就能跳转到后端通过程序得到结果再响应到前端页面呢?!

为了加深对该过程的理解,故以tomcat为例,撰写此文。

一、Tomcat部分

Tomcat总体结构:

Server->Service->Connector&Container(Engine->Host->Context(Wrapper(Servlet)))

前后端交互java 前后端交互流程图_服务器

 

 如图所示的Ttomcat结构图,其核心是Connector和Container组件,其中Connector组件可以被替换从而提供更多选择,因此一个Container可以选择对应多个Connector。

Server

多个Connector和一个Container就形成了一个Service,就有了对外提供服务的能力。而光有Service还不行,还必须给其一个生存环境去发挥去作用,这项生杀大权的掌握者就花落Server手中了。
因此,Tomcat的生命周期就由Server来控制。

Server的作用很简单,就是对外提供接口让其他程序能够访问到其中的Service集合,同时维护包含的所有Service的生命周期,如初始化、找到对应service和结束服务等。

Service

对于Service来说,主要是对外提供服务,其中的Connector主要是负责对外交流,而Container则是处理内部事务。一个Service可有多个Connector,但只能有一个Container。

前后端交互java 前后端交互流程图_服务器_02

Connector

对于Connector来说,它将在某个指定的端口上来监听客户请求,把从socket传递过来的数据封装成Request,传递给Engine来进行处理,并从Engine处获得响应并返回给客户。Tomcat通常会用到两种Connector:Http Connector,在端口8080处监听来自客户browser的http请求;AJP Connector,在端口8009处监听来自其他webServer的Servlet/jsp代理请求。

Container

 在Container核心组件中,包含了以下几个核心部分:Wrapper、Host、Engine、Context。

前后端交互java 前后端交互流程图_Servlet_03

其中Engine是负责处理所有相关联的service请求,并将结果返回给service。而Connector则是作为service和engine之间的桥梁。一个engine下可以配置一个默认主机,每个虚拟主机都有一个域名。当engine接收到一个请求时,它会将该请求匹配到虚拟主机(host)上,然后将请求交给host来处理。若无法匹配到虚拟主机,则将其交给默认host来处理,以线程方式来启动host。

Host代表一个虚拟主机,每个虚拟主机和某网络域名相匹配。每个虚拟主机下可以有一个或多个web应用,每个web应用对应于一个context,相对应有contextpath。当主机接收到请求时,会将该请求匹配到某个context上,然后把请求交给该context来处理。

一个Context对应于一个web应用。一个web应用由一个或多个servlet组成。context在创建时将根据配置文件$ CATALINA_HOME/conf/web.xml和$ WEBAPP_HOME/WEB-INF/web.xml载入Servlet类。当Context获得请求时,将在自己的映射表(mapping table)中寻找相匹配的Servlet类,如果找到,则执行该类,获得请求的回应,并返回。

Wrapper代表了一个Servlet,负责管理Servlet的装载、初始化、执行以及资源回收。wrapper的实现类是StandardWrapper,该类还实现了拥有一个Servlet初始化信息的ServletConfig。

Lifecycle:在编程中也有很多对象是具有生命周期的,从初始化、运行、回收等 会经历几个不同的阶段。 在tomcat中容器相关的好多组建都实现了Lifecycle接口,当tomcat启动时,其依赖的下层组件会全部进行初始化。 并且可以对每个组件生命周期中的事件添加监听器。例如当服务器启动的时候,tomcat需要去调用servlet的init方法和初始化容器等一系列操作,而停止的时候,也需要调用servlet的destory方法。而这些都是通过org.apache.catalina.Lifecycle接口来实现的。由这个类来制定各个组件生命周期的规范。

Tomcat-Servlet的过程:

1、Tomcat在启动时,会加载server;

 

前后端交互java 前后端交互流程图_http_04

2、Server启动时,会加载Service;

前后端交互java 前后端交互流程图_tomcat_05

3、Service中会加载Container;

前后端交互java 前后端交互流程图_tomcat_06

4、Container中的Wrapper含有Servlet;

前后端交互java 前后端交互流程图_Servlet_07

5、在HttpServlet中含有一些doGet、doPost、service等方法,用来处理各种类型的请求。

前后端交互java 前后端交互流程图_服务器_08

Tomcat Server处理一个http请求的过程:

假设来自客户的请求为:
http://localhost:8080/test/index.jsp

1) 请求被发送到本机端口8080,被在那里侦听的Coyote HTTP/1.1 Connector获得
2) Connector把该请求交给它所在的Service的Engine来处理,并等待来自Engine的回应
3) Engine获得请求localhost/test/index.jsp,匹配它所拥有的所有虚拟主机Host
4) Engine匹配到名为localhost的Host(即使匹配不到也把请求交给该Host处理,因为该Host被定义为该Engine的默认主机)
5) localhost Host获得请求/test/index.jsp,匹配它所拥有的所有Context
6) Host匹配到路径为/test的Context(如果匹配不到就把该请求交给路径名为""的Context去处理)
7) path="/test"的Context获得请求/index.jsp,在它的mapping table中寻找对应的servlet
8) Context匹配到URL PATTERN为*.jsp的servlet,对应于JspServlet类
9) 构造HttpServletRequest对象和HttpServletResponse对象,作为参数调用JspServlet的doGet或doPost方法
10)Context把执行完了之后的HttpServletResponse对象返回给Host
11)Host把HttpServletResponse对象返回给Engine
12)Engine把HttpServletResponse对象返回给Connector
13)Connector把HttpServletResponse对象返回给客户browser

二、Serlvet原理

从Tomcat部分我们可以看出,browser的请求在层层传递下最终在Servlet处进行请求的处理及响应。因此本部分主要围绕传递过来的请求和响应部分来进行阐述。

1、认知Servlet

作为Javaweb三大组件(Servlet,Filter,Listener)之一的Servlet,每一个都是唯一的,所能处理的请求是不同的。

Servlet是一种独立于平台和协议的服务器端的java应用程序,运行于java服务器中,可以动态扩展服务器能力,并采用请求-响应模式来提供web服务。

Servlet是一个单实例多线程的。只能被实例化一次,而每次service服务会开启新线程进行处理新请求。

2、Servlet生命周期

前面说到,在Tomcat核心组件Container中,一个web应用由一个或多个Servlet组成,而一个Context对应一个web应用,在创建时会去根据配置文件$ CATALINA_HOME/conf/web.xml和$ WEBAPP_HOME/WEB-INF/web.xml载入Servlet类。

因此Servlet的生命周期由web容器来负责,根据web.xml来加载对应的Servlet类。Servlet核心代码如下:

前后端交互java 前后端交互流程图_前后端交互java_09

在上图所示的五个方法中,其中init、service和destroy三个方法均为生命周期方法,在第一次被访问时出生,在关闭服务器时死亡。

init方法会在Servlet对象创建之后马上执行,且只执行一次

destroy方法会在Servlet被销毁之前调用也只执行一次

对于service方法,则可以被多次调用,每次处理请求时都是在调用该方法。

getServletConfig可以获得Servlet的配置信息。

getServletInfo方法可以获得Servlet信息。

前后端交互java 前后端交互流程图_tomcat_10

从Servlet.class文件中我们可以看到,与之相关联的由ServletConfig、ServletRequest、ServletResponse三个类,这三个类都是通过web容器传递给Servlet的。

其中,ServletConfig是在Servlet初始化时就通过web.xml文件解析传给了Servlet,后两个都是请求到达时调用Servlet.service时才传递过来的。

前后端交互java 前后端交互流程图_tomcat_11

在第一部分讲解Wrapper时也说过,它代表了一个Servlet。通过查询源码发现,StandardWrapper和StandardWrapperFacede都实现了ServletConfig接口,而 StandardWrapperFacade 是 StandardWrapper 门面类(门面设计模式)。所以传给 Servlet 的是 StandardWrapperFacade 对象,这个类能够保证从 StandardWrapper 中拿到 ServletConfig 所规定的数据,而又不把 ServletConfig 不关心的数据暴露给 Servlet。

 3、Servlet工作过程

 1)browser发出一个http请求;

2)Tomcat的Connector组件监听到该请求,其主线程会创建HttpServletRequest对象和HTTPServletResponse对象;

3)从请求URL中找到正确Servlet后,Tomcat为其创建或分配一个线程,同时将2中对象传递给该线程;

4)Tomcat调用Servlet的service()方法,会根据请求参数的不同来调用doGet()或doPost()等方法,并将结果返回到HTTPServletResponse对象中;

5)Tomcat将响应结果返回到browser。

三、HTTP与服务器的交互方式

1、http简介

HTTP协议,即超文本传输协议,基于TCP/IP通信协议来传输数据,工作于客户端-服务端架构上,通过URL向Web服务器(Apache服务器等)传输请求并得到响应。默认端口为80,也可以设置为8080等。

HTTP三点注意事项:

HTTP是无连接:无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间。

HTTP是媒体独立的:这意味着,只要客户端和服务器知道如何处理的数据内容,任何类型的数据都可以通过HTTP发送。客户端以及服务器指定使用适合的MIME-type内容类型。

HTTP是无状态:HTTP协议是无状态协议。无状态是指协议对于事务处理没有记忆能力。缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。另一方面,在服务器不需要先前信息时它的应答就较快。

2、http消息结构

客户端发送一个HTTP请求到服务器的请求消息包括以下格式:请求行(request line)、请求头部(header)、空行和请求数据四个部分组成,

下图给出了请求报文的一般格式。

前后端交互java 前后端交互流程图_Servlet_12

HTTP响应也由四个部分组成,分别是:状态行、消息报头、空行和响应正文。

前后端交互java 前后端交互流程图_服务器_13

3、请求方式

HTTP1.0有三种:get、post、head;

HTTP1.1新增了五种:options、put、delete、trace和connect。

前后端交互java 前后端交互流程图_服务器_14

其中较为常用的为get、post、delete和put,这大致对应着对该资源的查、改、删、增四个操作。

1)Get请求用于向服务器进行信息获取,是安全和幂等的。它仅仅是为了获取信息,不会影响资源的状态;所谓幂等,即对于同一个URL的多个请求返回的结果都一致。

get请求会将数据附在URL之后,以?来进行分割,参数之间以&来进行连接。对于非英文字母/数字等,都需要进行格式的转换。而由于其在URL进行拼接,对于涉及到密码等请求,是不安全的。

在HTTP协议中对URL长度并没有作出限制,而URL的最大长度其实和用户浏览器以及web服务器有关。如IE为2048,Google为8182,Apache(Server)为8192。

2)Post请求表示向服务器提交数据的一种请求,可能修改服务器上的资源,类似数据库的insert一样。post对于数据的提交是放置在http包的包体当中的理论上post请求是没有大小限制的,起限制作用的是服务器处理程序的处理能力。如IIS 6.0默认post数据最大为200KB,每个表单限制为100KB。post 的安全性比get高。

3)Put请求也是向服务端发送数据从而改变信息,类似于数据库的update一般。

4)Delete请求就是删除某一资源的,类似于数据库的delete操作。

四、SpringMVC下前后端交互过程

前后端交互java 前后端交互流程图_服务器_15

1、交互过程

由于目前接触的项目是建立在springMVC模式下的,故根据上图所示,在最后对SpringMVC下的请求响应过程进行解析:

1)用户发送一个URL请求到前端控制器DispatcherServlet

2)前端控制器将请求发给处理器映射器HandlerMapping,它会根据xml配置、注解等进行查找hander;

3)处理器映射器返回执行链HandlerExecutionChain(里面有handler对象,在它之前有多个interceptor拦截器);

4)前端控制器通过处理器适配器HandlerAdapter去执行Handler,不同的Handler由不同的适配器执行;

5)通过Handler处理器,即我们熟悉的Controller来处理业务逻辑;

6)处理完之后,返回ModelAndView对象,其中有视图名称,模型数据等;

7)HandlerAdapter将ModelAndView返回给DispatcherServlet;

8)DispatcherServlet将得到的ModelAndView传递给视图解析器ViewResolver进行解析;

9)ViewResolver解析后返回具体的视图View

10)前端控制器对视图View和数据进行渲染,将模型数据等填充到request域中;

11)将最终的视图返回给客户,产生response响应。

2、组件名词解释

前端控制器DispatcherServlet:接收请求响应结果,相当于转发器、中央处理器,减少了其他组件之间的耦合度;

处理器映射器HandlerMapping:根据请求URL查找handler;

处理器适配器HandlerAdapter:按特定规则去执行handler,故编写handler时按HandlerAdapter要求去做,这样适配器才可正确执行handler;

视图解析器ViewResolver:根据逻辑视图解析成真正的视图(View对象)

视图View:View是一个接口,实现类支持不同的View类型(jsp,PDF,Excel...)

 

因个人学识有限,若上述内容某处叙述不当,请指教!