2019独角兽企业重金招聘Python工程师标准>>>

上文说了简单的servlet解析过程。实际上,tomcat在解析servlet的 时候是吧连接器定位为满足以下三个条件:

1、必须事先接口org.apache.catalina.Connector

2. 必须创建请求对象,该请求对象的类必须实现接口org.apache.catalina.Request。

3. 必须创建响应对象,该响应对象的类必须实现接口org.apache.catalina.Response。

tomcat的连接器有很多种类:Coyote、mode_jk、mod_jk2和mode_webapp等。

来自浏览器的请求类型是有区别的http/0.9 http/1.0 http/1.1.

http/1.1又叫做持久连接,上文中一次请求处理完毕就关闭了socket。然而,在现实的页面请求中需要加载多种资源(js、img css)。如果每次请求都开启关闭连接那将是非常耗时的事情。http/1.1能够让浏览器和服务器保持一种持久化的连接,快速的相应请求。这样,请求的形式就和之前不同,他是一块编码的形式,并使用特殊头部transfer-encoding感知发送过来的数据信息。同时,如果浏览器有较大数据请求之前发送头部信息Expect: 100-continue头部到服务器,等待服务器的相应。如果服务器响应数据能够接受大数据请求,才真正的发送数据,避免先发送大数据而遭服务器拒绝而浪费了传输数据的带宽资源。

本文重点说明连接器的演进。

连接器的演进主要包括了以下几个方面:

1、处理请求不再只是一次处理一次请求,而是生成Processor池,用于处理多个连接请求。同事Processor处理器也不再是每次请求新生成实例处理请求,而是从池子中获取到一个处理器去完成请求。同时,实现了Processor处理方法异步化,让连接器线程能够继续接受其他的请求。

2、处理器线程和连接器线程通过wait() notifyAll()的方式进行线程间通信。

3、Processor处理器中,增加了标识符,KeepAlive、stopped和http11,为处理器在处理的过程中设定“路口”,及时相应请求的变化。

4、socket缓冲区大小不再是像前文一样设置为定值,而是通过获取连接器传递过来的参数设置缓冲区大小。

5、处理器的职能更加的丰富。

连接处理  parseConnection,针对不同的连接协议做不同的处理。

解析请求 parseRequest

解析头部 parseHeaders

6、去掉了静态处理器,暂时无法接受静态资源请求。

------------------------

1、连接器启动:

HttpConnector connector = new HttpConnector();
SimpleContainer container = new SimpleContainer();
connector.setContainer(container);
try {
//初始化连接器,打开socket连接
connector.initialize();
//开启监听,开启连接器线程、将处理器线程启动并入队列。
connector.start();System.in.read();
}
catch (Exception e) {e.printStackTrace();
}

1.1 初始化连接、打开socket连接(使用工厂模式)

public void initialize()
throws LifecycleException {
//初始化标志,不能重复初始化
if (initialized)
throw new LifecycleException (
sm.getString("httpConnector.alreadyInitialized"));
this.initialized=true;Exception eRethrow = null;
// Establish a server socket on the specified port
try {
//打开socket连接
serverSocket = open();} catch (IOException ioe) {log("httpConnector, io problem: ", ioe);eRethrow = ioe;} catch (KeyStoreException kse) {log("httpConnector, keystore problem: ", kse);eRethrow = kse;} catch (NoSuchAlgorithmException nsae) {log("httpConnector, keystore algorithm problem: ", nsae);eRethrow = nsae;} catch (CertificateException ce) {log("httpConnector, certificate problem: ", ce);eRethrow = ce;} catch (UnrecoverableKeyException uke) {log("httpConnector, unrecoverable key: ", uke);eRethrow = uke;} catch (KeyManagementException kme) {log("httpConnector, key management problem: ", kme);eRethrow = kme;}
if ( eRethrow != null )
throw new LifecycleException(threadName + ".open", eRethrow);
}
private ServerSocket open()
throws IOException, KeyStoreException, NoSuchAlgorithmException,CertificateException, UnrecoverableKeyException,KeyManagementException
{
// Acquire the server socket factory for this Connector//获得服务器socket工厂实例
ServerSocketFactory factory = getFactory();
// If no address is specified, open a connection on all addresses//如果没有指定地址,在所有地址上打开一个连接
if (address == null) {log(sm.getString("httpConnector.allAddresses"));
try {
return (factory.createSocket(port, acceptCount));} catch (BindException be) {
throw new BindException(be.getMessage() + ":" + port);}}
//在指定地址上打开一个连接
try {InetAddress is = InetAddress.getByName(address);log(sm.getString("httpConnector.anAddress", address));
try {
return (factory.createSocket(port, acceptCount, is));} catch (BindException be) {
throw new BindException(be.getMessage() + ":" + address +
":" + port);}} catch (Exception e) {log(sm.getString("httpConnector.noAddress", address));
try {
return (factory.createSocket(port, acceptCount));} catch (BindException be) {
throw new BindException(be.getMessage() + ":" + port);}}
}

1.2、开启监听,开启连接器线程、将处理器线程启动并入队列。

//为连接器绑定指定数量的处理器
public void start() throws LifecycleException {
//判断该线程的connect开启状态,避免重复开启
if (started)
throw new LifecycleException(sm.getString("httpConnector.alreadyStarted"));
threadName = "HttpConnector[" + port + "]";
//打开监听
lifecycle.fireLifecycleEvent(START_EVENT, null);
started = true;
// Start our background thread//开启一个后台连接器线程
threadStart();
//创建处理器,并调用recyle方法将其放置到栈队列中
while (curProcessors < minProcessors) {
if ((maxProcessors > 0) && (curProcessors >= maxProcessors))
break;HttpProcessor processor = newProcessor();recycle(processor);}
}

2、连接器、容器之间的协作关系

2.1 容器派发socket到处理器线程

public void run() {
// Loop until we receive a shutdown command//开启循环,知道我们获得了结束命令
while (!stopped) {
// Accept the next incoming connection from the server socket
Socket socket = null;
try {//获得socket请求
socket = serverSocket.accept();//  设置超时时间
if (connectionTimeout > 0)socket.setSoTimeout(connectionTimeout);
//设置tcp nodelay属性
socket.setTcpNoDelay(tcpNoDelay);} catch (AccessControlException ace) {
//抛出连接安全错误信息
log("socket accept security exception", ace);
continue;} catch (IOException e) {
try {
// If reopening fails, exit//如果再次开启失败,退出
synchronized (threadSync) {
if (started && !stopped)log("accept error: ", e);
if (!stopped) {
//  关闭异常连接
serverSocket.close();             //   重新开启异常连接
serverSocket = open();}}
//  异常处理,包括不限于秘钥等错误请求
} catch (Exception ioe) {log("socket reopen, io problem: ", ioe);
break;}
continue;}   //判断处理器栈是否有可用处理器,没有按规则生成,有则获取栈中处理器
HttpProcessor processor = createProcessor();
//获取处理器为空,可能情况是请求数量过多,超过了承受的最大处理器个数
if (processor == null) {
try {log(sm.getString("httpConnector.noProcessor"));socket.close();} catch (IOException e) {;}
continue;}
//派发socket到处理器
processor.assign(socket);
// The processor will recycle itself when it finishes
}
//获取到了结束命令,通知其他线程
synchronized (threadSync) {
threadSync.notifyAll();}
}

2.2处理器接收到派发socket

synchronized void assign(Socket socket) {
// d等待该处理器的其它socket处理执行完毕
while (available) {
try {wait();} catch (InterruptedException e) {}}
// Store the newly available Socket and notify our thread//将新获取的socket放置到处理器中,并发送线程通知
this.socket = socket;
available = true;notifyAll();
if ((debug >= 1) && (socket != null))log(" An incoming request is being assigned");
}

2.3  处理器接收到了socket请求,准备处理

public void run() {
// Process requests until we receive a shutdown signal
while (!stopped) {
// Wait for the next socket to be assigned//等待连接器的socket请求
Socket socket = await();
if (socket == null)
continue;
// Process the request from this socket
try {
//处理socket请求
process(socket);} catch (Throwable t) {log("process.invoke", t);}
// Finish up this request//处理完毕,将该processor线程归还给Stack processors 用来处理接下来的socket请求
connector.recycle(this);}
// Tell threadStop() we have shut ourselves down successfully
synchronized (threadSync) {
//该处理器线程退出,通知其他processor
threadSync.notifyAll();}
}

未完待续

转载于:https://my.oschina.net/zjItLife/blog/608576

servlet解析演进(2-1)相关推荐

  1. 【Ajax】第一课 Ajax访问Servlet解析Json格式

    概念 ajax(Web数据交互方式),Ajax即Asynchronous Javascript And XML(异步JavaScript和XML)在 2005年被Jesse James Garrett ...

  2. [estore基础知识] 之(二)【Spring MVC和原始servlet方式演进】

    1. 最初不使用框架,只使用servlet实现MVC模式的方式为: (1)在web.xml中配置servlet, servlet-mapping, 配置http请求进入不同的servlet中, 这里可 ...

  3. Servlet获得Http请求,GET/POST

    Servlet获得Http请求 Http请求信息格式 请求行(方法提交方式,URI,Http协议版本) GET方式提交:URI会包含查询字符串 POST方式提交:URI不会包含查询字符串 请求头 Ho ...

  4. Servlet获取Excel中数据的两种方式

    Servlet解析Excel文件的两种方式 简单分享一下Servlet通过解析Excel文件得到其中数据的两种方式 第一种:前端获取 思路:通过layui的第三方插件 layui.excel 解析ex ...

  5. 【Java成王之路】EE初阶第二十四篇: Servlet

    Sevlet Servlet 是什么 Servlet 是一种实现动态页面的技术. 是一组 Tomcat 提供给程序猿的 API, 帮助程序猿简单高效的开发一 个 web app. Tomcat 是一个 ...

  6. Servlet知识点小结

    文章目录 1.Servlet简介 2.Http简介 3.URL简介 4.Servlet的体系结构 4.1 **Servlet接口:定义了五个抽象方法** 4.2 **GenericServlet抽象类 ...

  7. Servlet生命周期总结

    servlet的执行原理与生命周期 一.先从servlet容器说起:大家最为熟悉的servlet容器就是Tomcat ,Servlet 容器是如何管理 Servlet? 先看一下tomcat的容器模型 ...

  8. Servlet的执行原理与生命周期

    先从 Servlet 容器说起:大家最为熟悉的 Servlet 容器就是 Tomcat ,Servlet 容器是如何管理 Servlet 的? 先看一下 Tomcat 的容器模型: 从上图可以看出 T ...

  9. 可爱的javaee:非框架架构漫谈

    概述 你可以说可爱的php ,可爱的ror ,可爱的python ,甚至可爱的.net ,但是javaee ?他太复杂了.相比前三种技术,javaee 的技术体系更全面.更规整也更复杂,他的复杂性也让 ...

最新文章

  1. R语言ggplot2可视化在ggplot2生成的可视化结果下方显示文本:显示一些关于数据的信息
  2. 程序员经常去的 14 个顶级开发者社区(转)
  3. Update item to this version和Revert to this version区别
  4. Codeforces Round #359 div2
  5. Linux+Docker+腾讯云/阿里云服务器 安装MySQL相关命令整理
  6. SpringCloud学习笔记014---可以使用json对rabbitmq进行封装,方便数据传输
  7. UI学习笔记---EasyUI panel插件使用---03
  8. MarkDown、Vim双剑合璧
  9. python 随机数_Python中的随机数
  10. 拓端tecdat|R语言在不同样本量下的Little‘s MCAR检验
  11. 在Cesium中实现与CAD的DWG图叠加显示分析
  12. lan pci 联想开机_联想笔记本bios怎么设置 联想笔记本进入bios方法【详解】
  13. Siamese 目标跟踪:Learning to Fuse Asymmetric Feature Maps in Siamese Trackers(CVPR2021)
  14. 三自由度机器人轨迹规划(两旋转+移动)
  15. Excel获取Sheet名称公式
  16. 将ShellCode注入进程内存
  17. C++随机生成字符串,亲测可用,简单易懂
  18. 拓嘉辰丰电商:拼多多新品适合场景推广还是搜索推广
  19. 记录:MySQL报错1075 - Incorrect table defintion;there can be only...【解决方案】
  20. Android一个通用的下拉框适配器(kotlin版本)

热门文章

  1. python 常用内置函数_Python小白必备的8个最常用的内置函数(推荐)
  2. 如何删除tmp计算机桌面,Win10系统中tmp文件删除不了应该如何解决?
  3. 跨境电商自建站后台系统原型rp_没学历做跨境电商好做吗?虾皮shopee开店没有流水怎么办...
  4. python pandas读取csv_Python3 pandas怎么读取csv文件的第一行的
  5. qpython3l手机版怎么用_qpython怎么用
  6. php 函数静态变量,php 函数中静态变量使用的问题实例分析
  7. Mybatis执行过程源码分析
  8. 串结构练习——字符串连接
  9. 【Tools】CSDN中如何添加数学公式
  10. [Google Guava] 1.1-使用和避免null