手写服务器笔记记录与tomcat相关笔记(无源码)

2021-08-19 14:58:54 浏览数 (1)

目录

    • @[TOC](目录)
    • 1. 前言
    • 2. 逻辑推导
    • 3. 关键问题:
    • 4. servlet
    • 5. 问题思考
    • 6. 图解与说明
    • 7. 优化
      • servlet缓存池
      • servlet线程安全
    • 8. 应用联想
    • 9. 推荐阅读
    • 10. 关键信息记录

1. 前言

阅读之前,请先理解以下概念:

  • web服务器:如tomcat,它是web应用的载体。由于我们平时老是说“客户端与服务端进行交互”,然后容易误以为我们写的web应用就是服务器,这种理解是错误的。web服务器相当于一个容器,装载着我们写的web应用,与浏览器进行交互的是web服务器,处理逻辑的是我们的web应用。
  • webApp(web应用):
  • servlet:web应用中处理业务逻辑的类(或者说处理request返回response的类)
  • HTTP:这个自行百度,主要理解三次握手、请求与响应

2. 逻辑推导

从已有知识推导服务器逻辑: start–>

  1. 浏览器与服务器直接通过HTTP协议进行数据传输==》
  2. HTTP协议分为请求报文和响应报文,浏览器发送请求报文,服务器返回响应报文==》
  3. 请求报文中关键数据包括:请求路径(统一资源定位符),请求体(发送的数据包);响应报文中关键数据包括:响应体(响应的数据包)==》
  4. 所以,大概逻辑如下==》
  5. 浏览器通过IO流发送请求资源路径和请求数据包给服务端==》
  6. 服务端获取IO流,得到请求路径和请求数据包==》
  7. 根据请求路径找到对应的请求资源,并处理响应的数据包==》
  8. 将上述过程的结果封装到响应体中,通过IO流返回。

end<–

3. 关键问题:

  1. 如何利用统一资源定位符找到对应的服务器资源?
  2. IO流传输的是字节流,html页面最终是怎样渲染到浏览器的?

回答: 如果是静态的html页面,则直接根据uri找到服务器中的静态页面,然后通过IO流返回。 直接返回的是字符串,这个解析过程,只要带上对应的响应协议,浏览器会自动渲染。

4. servlet

问:如果是xxx.html结尾,显然只需要读取服务器html资源然后响应即可,但是对于?username=xx&psw=xxx这样的uri,需要业务逻辑来处理,该如何解决?

答:显然,这种写法也是HTTP规范之一,因此,也可以通过遵守规范而正确解析。服务器只做转发功能(web),而逻辑功能,则是服务来完成(webApp),这类webApp,就是servlet。(server Applet的缩写) 关键逻辑如下:

  1. 浏览器发送的/project/login?username=xx&psw=xxx,到达web服务器
  2. web服务器根据HTTP协议,首先解析uri问号的前半部分/project/login,然后建立uri与servlet的映射关系(这就是web.xml的由来),并通过解析web.xml反射得到servlet,然后解析得到参数键值对并封装到request中(同时初始化响应的response请求头,避免由webApp来拼接响应头协议)
  3. 通过servlet.service(request,response)调用webapp中的servlet,执行相关的do方法。

关键知识: 这里面有两大规范:HTTP协议、servlet规范 HTTP协议制定浏览器与服务器之间的交互规则,体现在HTTP请求与HTTP响应上。 servlet规范制定了服务器与webApp之间的交互规则。体现在:webApp的servlet实现servlet规范,然后在web服务器中,直接通过servlet接口调用具体实现。

5. 问题思考

为什么需要web.xml文件(或者相关的注解)? web.xml文件中定义了uri与servlet的映射关系,如果不在配置文件中定义,那就只能在web服务器启动类的解析过程中预先定义所有uri与servlet的关系映射,这显然不可能。只能通过反射获取。

6. 图解与说明

  1. 端口开发JDK 的ServerSocket已提供相应方法
  2. socket网络编程主要包含端口监听、请求监听、解析输入流得到请求、构建输出流进行响应。
  3. 线程调度器即线程池,每个请求都会从池中拿一个线程进行执行,可以用ExecutorService创建
  4. servlet需要解析web.xml文件得到url与servlet映射关系,然后解析浏览器传递过来的url,用反射获取对应的servlet进行执行。

7. 优化

servlet缓存池

如果解析完url之后就直接根基web.xml中的映射关系反射获取servlet,这样必定出现servlet爆炸(每个相同的url都会创建一个servlet)。 因此需要建立一个servlet缓存池。 逻辑: 维护一个url:servlet缓存池。 请求过来之后,先从池中拿,拿不到,再反射创建一个,同时放到池中。

servlet线程安全

对于相同的url,servlet都是同一个,即会有多个用户同时使用同一个servlet对象的情况,自然可能存在线程安全。

一般只用一种方式进行规范,那就是不要定义会变化的servlet的成员变量。 非要使用的话,请用TheadLocal

8. 应用联想

springmvc的dispatchservlet也是一个servlet,只不过他不直接处理请求与响应,而是做请求与响应的中转站。


springboot中的web开发,controller也有线程安全问题,原因与servlet相同,解决办法也相同。

9. 推荐阅读

TomCat架构分析

Tomcat连接器

Tomcat配置文件详解(配置文件基本展现了Tomcat的架构,建议重视)

servlet工作原理

另外,还可以打开百度图片,搜索 “tomcat架构图” “tomcat时序图” 等图。

10. 关键信息记录

  1. 在初始化过程中,tomcat大量使用观察者模式,以便于实现链式初始化
  2. 容器层级之间基于pipeline(管道)和valve(阀门)的形式处理request(类似过滤器、责任链)相当于提供了可在每层容器之间设置过滤器的功能
  3. tomcat没有遵循双亲委派类加载机制,而是自定义类加载顺序。原因:tomcat本身是一个java程序(即便它运行着多个不同的java项目),如果还是按照双亲委派,则多个不同的项目可能发生冲突,比如说不同项目中相同的类名。因此,基本要求就是不同的webapp应该用各自不同的类加载器。 (延伸阅读)

0 人点赞