阅读 85

深入拆解Tomcat & Jetty-学习笔记(1)模块一之必备基础

模块一 必备基础

01 HTTP协议必知必会的知识

http请求过程

  1. 用户通过浏览器进行了一个操作,比如输入网址并回车,或者是点击链接,接着浏览器获取了这个事件。
  2. 浏览器向服务端发出 TCP 连接请求。
  3. 服务程序接受浏览器的连接请求,并经过 TCP 三次握手建立连接。
  4. 浏览器将请求数据打包成一个 HTTP 协议格式的数据包。
  5. 浏览器将该数据包推入网络,数据包经过网络传输,最终达到端服务程序。
  6. 服务端程序拿到这个数据包后,同样以 HTTP 协议格式解包,获取到客户端的意图。
  7. 得知客户端意图后进行处理,比如提供静态文件或者调用服务端程序获得动态结果。
  8. 服务器将响应结果(可能是 HTML 或者图片等)按照 HTTP 协议格式打包。
    1. 服务器将响应数据包推入网络,数据包经过网络传输最终达到到浏览器。
  9. 浏览器拿到数据包后,以 HTTP 协议的格式解包,然后解析数据,假设这里的数据是 HTML。
  10. 浏览器将 HTML 文件展示在页面上。
http请求响应实例

请求:请求行,请求头,请求体 响应:状态行,响应报文,报文主体

cookie和session

Cookie 本质上就是一份存储在用户本地的文件,里面包含了每次请求中都需要传递的信息

Session 可以理解为服务器端开辟的存储空间,里面保存了用户的状态

当用户请求到来时,服务端可以把用户的请求和用户的 Session 对应起来。那么 Session 是怎么和请求对应起来的呢?答案是通过 Cookie,浏览器在 Cookie 中填充了一个 Session ID 之类的字段用来标识请求。

关于restful风格的理解

将网络上的信息实体看作是资源,可以是图片、文件、一个服务...资源用URI统一标识,URI中没有动词哦,这是因为它是资源的标识,那怎么操作这些资源呢,于是定义一些动作:GET、POST、PUT和DELETE。通过URI+动作来操作一个资源。

关于Http无状态的请求的理解

所谓的无状态说的是,为了完成一个操作,请求里包含了所有信息,你可以理解为服务端不需要保存请求的状态,也就是不需要保存session,没有session的好处是带来了服务端良好的可伸缩性,方便failover,请求被LB转到不同的server实例上没有差别。从这个角度看,正是有了REST架构风格的指导,才有了HTTP的无状态特性,顺便提一下,REST和HTTP1.1出自同一人之手。但是理想是丰满的,现实是骨感的,为了方便开发,大多数复杂的Web应用不得不在服务端保存Session。为了尽量减少Session带来的弊端,往往将Session集中存储到Redis上,而不是直接存储在server实例上。

关于http长连接的理解以及1.0和1.1和2.0的区别

在 HTTP/1.0 时期,每次 HTTP 请求都会创建一个新的 TCP 连接,请求完成后之后这个 TCP 连接就会被关闭。这种通信模式的效率不高 HTTP/1.1 中,引入了 HTTP 长连接的概念,使用长连接的 HTTP 协议,会在响应头加入 Connection:keep-alive。这样当浏览器完成一次请求后,浏览器和服务器之间的 TCP 连接不会关闭,再次访问这个服务器上的网页时,浏览器会继续使用这一条已经建立的连接,也就是说两个请求可能共用一个 TCP 连接。 HTTP/1.1中的长连接依然没有解决 head of line blocking 的问题,后面的连接必须等待前面的返回了才能够发送,这个问题直到HTTP/2.0采取二进制分帧编码方式才彻底解决。

02.servlet规范和servlet容器

servlet和servlet容器的关系

Servlet 本质上是一个接口,实现了 Servlet 接口的业务类也叫 Servlet。Servlet 接口其实是 Servlet 容器跟具体 Servlet 业务类之间的接口。Servlet 接口跟 Servlet 容器这一整套规范叫作 Servlet 规范,而 Servlet 规范使得程序员可以专注业务逻辑的开发,同时 Servlet 规范也给开发者提供了扩展的机制 Filter 和 Listener。


public interface Servlet {
    void init(ServletConfig config) throws ServletException;
    
    ServletConfig getServletConfig();
    
    void service(ServletRequest req, ServletResponse res)throws ServletException, IOException;
    
    String getServletInfo();
    
    void destroy();
}
复制代码
Servlet容器工程流程

  1. 当客户请求某个资源时,HTTP 服务器会用一个 ServletRequest 对象把客户的请求信息封装起来
  2. 然后调用 Servlet 容器的 service 方法,Servlet 容器拿到请求后,根据请求的 URL 和 Servlet 的映射关系,找到相应的 Servlet
  3. 如果 Servlet 还没有被加载,就用反射机制创建这个 Servlet,并调用 Servlet 的 init 方法来完成初始化
  4. 接着调用 Servlet 的 service 方法来处理请求,把 ServletResponse 对象返回给 HTTP 服务器,HTTP 服务器会把响应发送给客户端。
什么是ServletContext

Servlet 规范里定义了 ServletContext 这个接口来对应一个 Web 应用。Web 应用部署好后,Servlet 容器在启动时会加载 Web 应用,并为每个 Web 应用创建唯一的 ServletContext 对象。你可以把 ServletContext 看成是一个全局对象,一个 Web 应用可能有多个 Servlet,这些 Servlet 可以通过全局的 ServletContext 来共享数据,这些数据包括 Web 应用的初始化参数、Web 应用目录下的文件资源等。由于 ServletContext 持有所有 Servlet 实例,你还可以通过它来实现 Servlet 请求的转发。

什么是Filter

Filter 是过滤器,这个接口允许你对请求和响应做一些统一的定制化处理,比如你可以根据请求的频率来限制访问,或者根据国家地区的不同来修改响应内容。过滤器的工作原理是这样的:Web 应用部署完成后,Servlet 容器需要实例化 Filter 并把 Filter 链接成一个 FilterChain。当请求进来时,获取第一个 Filter 并调用 doFilter 方法,doFilter 方法负责调用这个 FilterChain 中的下一个 Filter。

什么是Listener

Listener 是监听器,这是另一种扩展机制。当 Web 应用在 Servlet 容器中运行时,Servlet 容器内部会不断的发生各种事件,如 Web 应用的启动和停止、用户请求到达等。 Servlet 容器提供了一些默认的监听器来监听这些事件,当事件发生时,Servlet 容器会负责调用监听器的方法。当然,你可以定义自己的监听器去监听你感兴趣的事件,将监听器配置在web.xml中。比如 Spring 就实现了自己的监听器,来监听 ServletContext 的启动事件,目的是当 Servlet 容器启动时,创建并初始化全局的 Spring 容器。

Filter和Listener以及(intercepter )拦截器的关系

1.Filter是Servlet规范的一部分,是Servlet容器Tomcat实现的。 2.Intercepter是Spring发明的。 3.它们的执行顺序是: Filter.doFilter(); HandlerInterceptor.preHandle(); Controller; HandlerInterceptor.postHandle(); DispatcherServlet 渲染视图 HandlerInterceptor.afterCompletion(); Filter.doFilter(); Servlet方法返回;

Filter 是干预过程的,它是过程的一部分,是基于过程行为的。 Listener 是基于状态的,任何行为改变同一个状态,触发的事件是一致的。

servlet容器和Spring容器和SpringMVC容器之间的关系

Servlet容器,是用于管理Servlet生命周期的。 Spring容器,是用于管理Spring Bean生命周期的,如service,dao等。 SpringMVC容器,适用于管理SpringMVC Bean生命周期的,如Controller,ViewResovler等。

Tomcat/Jetty启动,对于每个WebApp,依次进行初始化工作:

  1. 对每个WebApp,都有一个WebApp ClassLoader,和一个ServletContext

  2. ServletContext启动时,会扫描web.xml配置文件,找到Filter、Listener和Servlet配置

  3. 如果Listener中配有spring的ContextLoaderListener

    • ContextLoaderListener就会收到webapp的各种状态信息。
    • 在ServletContext初始化时,ContextLoaderListener也就会将Spring IOC容器进行初始化,管理Spring相关的Bean。
    • ContextLoaderListener会将Spring IOC容器存放到ServletContext中
  4. 如果Servlet中配有SpringMVC的DispatcherServlet

    • DispatcherServlet初始化时(其一次请求到达初始化,延迟加载)。
    • 其中,DispatcherServlet会初始化自己的SpringMVC容器,用来管理Spring MVC相关的Bean。
    • SpringMVC容器可以通过ServletContext获取Spring容器,并将Spring容器设置为自己的根容器。而子容器可以访问父容器,从而在Controller里可以访问Service对象,但是在Service里不可以访问Controller对象。

附一个描述关系的图 blog.csdn.net/zhanglf02/a…

纯手工打造一个Servlet

基本步骤
  1. 下载并安装 Tomcat。
  2. 编写一个继承 HttpServlet 的 Java 类。
  3. 将 Java 类文件编译成 Class 文件。
  4. 建立 Web 应用的目录结构,并配置web.xml。
  5. 部署 Web 应用。
  6. 启动 Tomcat。
  7. 浏览器访问验证结果。
  8. 查看 Tomcat 日志。
目录介绍
  1. /bin:存放 Windows 或 Linux 平台上启动和关闭 Tomcat 的脚本文件。
  2. /conf:存放 Tomcat 的各种全局配置文件,其中最重要的是server.xml。
  3. /lib:存放 Tomcat 以及所有 Web 应用都可以访问的 JAR 文件。
  4. /logs:存放 Tomcat 执行时产生的日志文件。
  5. /work:存放 JSP 编译后产生的 Class 文件。
  6. /webapps:Tomcat 的 Web 应用目录,默认情况下把 Web 应用放在这个目录下。
日志目录介绍

这里简要介绍各个文件的含义。

  1. catalina.xxx.log主要是记录 Tomcat 启动过程的信息,在这个文件可以看到启动的 JVM 参数以及操作系统等日志信息。
  2. catalina.outcatalina.out是 Tomcat 的标准输出(stdout)和标准错误(stderr),这是在 Tomcat 的启动脚本里指定的,如果没有修改的话 stdout 和 stderr 会重定向到这里。所以在这个文件里可以看到我们在MyServlet.java程序里打印出来的信息:MyServlet 在处理 get 请求…
  3. localhost.xx.log主要记录 Web 应用在初始化过程中遇到的未处理的异常,会被 Tomcat 捕获而输出这个日志文件。
  4. localhost_access_log.xx.txt存放访问 Tomcat 的请求日志,包括 IP 地址以及请求的路径、时间、请求协议以及状态码等信息。
  5. manager.xxx.log/host-manager.xxx.log存放 Tomcat 自带的 Manager 项目的日志信息。
web.xml配置和 @WebServlet注解配置

以下两种配置都可以将servlet注给servlet容器

 <servlet>      
     <servlet-name>myServlet</servlet-name>      
     <servlet-class>MyServlet</servlet-class>   
 </servlet>    
 <servlet-mapping>     
     <servlet-name>myServlet</servlet-name>   
     <url-pattern>/myservlet</url-pattern>   
 </servlet-mapping>
复制代码
@WebServlet("/myAnnotationServlet")
public class AnnotationServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
    //TODO
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
    //TODO

}  
复制代码
注意

Servlet接口中定义了service方法,没有doGet/doPost。HttpServlet是一个实现类,实现了service方法,同时留出了doGet/doPost方法让程序员来实现。

备注

本文是我个人学习了李号双老师的专栏课程之后,结合专栏文章和老师对同学答疑整理的学习笔记。仅供分享。更多精彩内容,大家可以扫描下方二位码,在极客时间订阅李号双老师的《深入拆解Tomcat & Jetty》。获取一手学习资料。

关注下面的标签,发现更多相似文章
评论