系列文章目录
如何创建一个Servlet项目(Maven)?_crazy_xieyi的博客-CSDN博客
Tomcat下载、安装及使用介绍_crazy_xieyi的博客-CSDN博客
文章目录
Servlet 运行原理
在 Servlet 的代码中我们并没有写 main 方法, 那么对应的 doGet 代码是如何被调用的呢? 响应又是如何返回给浏览器的?
我们自己的实现是在
Tomcat 基础上运行的。当浏览器给服务器发送请求的时候
, Tomcat
作为
HTTP
服务器
,
就可以
接收到这个请求。
详细的交互过程示意图:
1) 接收请求:
用户在浏览器输入一个
URL,
此时浏览器就会构造一个
HTTP
请求。
这个
HTTP
请求会经过网络协议栈逐层进行
封装
成二进制的
bit
流
,
最终通过物理层的硬件设备转
换成光信号
/
电信号传输出去。
这些承载信息的光信号
/
电信号通过互联网上的一系列网络设备
,
最终到达目标主机
(
这个过程也需
要网络层和数据链路层参与
)。
服务器主机收到这些光信号
/
电信号
,
又会通过网络协议栈逐层进行
分用
,
层层解析
,
最终还原成
HTTP
请求。
并交给
Tomcat
进程进行处理
(
根据端口号确定进程
)。
Tomcat
通过
Socket
读取到这个请求
(
一个字符串
),
并按照
HTTP
请求的格式来解析这个请求
,
根据
请求中的
Context Path
确定一个
webapp,
再通过
Servlet Path
确定一个具体的 类
.
再根据当前请
求的方法
(GET/POST/...),
决定调用这个类的
doGet
或者
doPost
等方法
.
此时我们的代码中的
doGet / doPost
方法的第一个参数
HttpServletRequest
就包含了这个
HTTP
请求的详细信息。
2) 根据请求计算响应:
在我们的
doGet / doPost
方法中
,
就执行到了我们自己的代码。
我们自己的代码会根据请求中的一
些信息
,
来给
HttpServletResponse
对象设置一些属性
.
例如状态码
, header, body
等。
3) 返回响应:
我们的
doGet / doPost
执行完毕后
, Tomcat
就会自动把
HttpServletResponse
这个我们刚设置
好的对象转换成一个符合
HTTP
协议的字符串
,
通过
Socket
把这个响应发送出去。
此时响应数据在服务器的主机上通过网络协议栈层层
封装
,
最终又得到一个二进制的
bit
流
,
通过
物理层硬件设备转换成光信号
/
电信号传输出去。
这些承载信息的光信号
/
电信号通过互联网上的一系列网络设备
,
最终到达浏览器所在的主机
(
这个
过程也需要网络层和数据链路层参与
)。
浏览器主机收到这些光信号
/
电信号
,
又会通过网络协议栈逐层进行
分用
,
层层解析
,
最终还原成
HTTP
响应
,
并交给浏览器处理。
浏览器也通过
Socket
读到这个响应
(
一个字符串
),
按照
HTTP
响应的格式来解析这个响应
.
并且把
body
中的数据按照一定的格式显示在浏览器的界面上。
二、Tomcat 是如何初始化/处理请求的?
Tomcat
的代码中内置了
main
方法
.
当我们启动
Tomcat
的时候
,
就是从
Tomcat
的
main
方法开
始执行的。
被
@WebServlet
注解修饰的类会在
Tomcat
启动的时候就被获取到
,
并集中管理。
Tomcat
通过
反射
这样的语法机制来创建被
@WebServlet
注解修饰的类的实例。
这些实例被创建完了之后
,
会调用其中的
init
方法进行初始化
. (
这个方法是
HttpServlet
自带的
,
我们自己写的类可以重写
init)。
这些实例被销毁之前
,
会调用其中的
destory
方法进行收尾工作
. (
这个方法是
HttpServlet
自带的
,
我们自己写的类可以重写
destory)。
Tomcat
内部也是通过
Socket API
进行网络通信。
Tomcat
为了能同时相应多个
HTTP
请求
,
采取了多线程的方式实现
.
因此
Servlet
是运行在
多线程
环境
下的。
2.Tomcat 处理请求
Tomcat
从
Socket
中读到的
HTTP
请求是一个字符串
,
然后会按照
HTTP
协议的格式解析成一个
HttpServletRequest
对象。
Tomcat
会根据
URL
中的
path
判定这个请求是请求一个静态资源还是动态资源
.
如果是静态资源
,
直接找到对应的文件把文件的内容通过
Socket
返回
.
如果是动态资源
,
才会执行到
Servlet
的相关
逻辑。
Tomcat
会根据
URL
中的
Context Path
和
Servlet Path
确定要调用哪个
Servlet
实例的
service
方法。
通过
service
方法
,
就会进一步调用到我们之前写的
doGet
或者
doPost。
3.Servlet 的 service 方法
Servlet
的
service
方法内部会根据当前请求的方法
,
决定调用其中的某个
doXXX
方法。
在调用 doXXX 方法的时候, 就会触发 多态 机制, 从而执行到我们自己写的子类中的 doXXX 方法。
自己写的
类
,
继承自
HttpServlet
类
.
而
HttpServlet
又继承自
Servlet.
相当于自己写的类
就是
Servlet 的子类。
接下来
,
在
Tomcat
启动阶段
, Tomcat
已经根据注解的描述
,
创建了
自己写的类
的实例
,
然后把
这个实例放到了
Servlet 数组中。
后面我们根据请求的
URL
从数组中获取到了该
实例
,
但是我们是通过
Servlet ins
这样的父类引用来获取到该实例的。
最后
,
我们通过
ins.doGet()
这样的代码调用
doGet
的时候
,
正是
"
父类引用指向子类对象
",
此
时就会触发多态机制
,
从而调用到我们之前写的类
中所实现的
doGet
方法。
等价代码
:
Servlet ins = new HelloServlet();
ins.doGet(req, resp);