博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Servlet容器原型(二)——一个简单的连接器
阅读量:7038 次
发布时间:2019-06-28

本文共 2531 字,大约阅读时间需要 8 分钟。

hot3.png

在(一)的基础上增加了,一个连接器,负责解析HTTP请求头,使servlet实例能够获得到请求头,cookie和请求参数/值等信息。

下面是这个应用程序的类图:

151929_X4to_265349.png

Bootstrap类很简单,代码如下:

public final class Bootstrap{    public static void main(String[] args){        HttpConnector connector = new HttpConnector();         connector.start();       }}

就是负责启动连接器来监听客户端的连接,与(一)相比,这个启动的任务与监听连接的任务分割了开来。

而HttpConnector就是负责监听和处理这个连接的,在连接到来取得代表客户端的Socket之后,将其交给HttpProcessor。

从UML类图中可以看出,HttpProcessor要与ServletProcessor和StaticResourceProcessor组合在一起,那么究竟用那一个处理器去处理呢,就得先处理客户端的Request了,同样,这两个对象在到达程序员自己定义的Servlet之前已经实例化好,而在(二)里面就是HttpRequest和HttpRespose;那么在这之前先得做的工作就是parseRequest()和parseHeaders()了,它们都是HttpProcessor的私有函数。

下面来了解如何解析HTTP请求,主要分层五个部分:

  1. 读取套接字输入流;

  2. 解析请求行;

  3. 解析请求头

  4. 解析Cookie

  5. 获取参数

分别解释下上面的步骤:

  1. 获取套接字就是为了后面的使用而准备的,这里用org.apache.catalina.connector.http.SocketInputStream来包装以下原始的InputStream,用SocketInputStream的好处就是方便使用它的readRequestLine()方法和readHeader()方法。

  2. 解析请求行就是在parseRequest(SocketInputStream sis, OutputStream out)方法里面进行的,它解析出了HTTP请求的方法,URI,协议版本,还有查询字段(如果有的话),并将相应的信息填充到HttpRequest对象当中。这个原始的URI可能是相对路径,类似 /hostname/someResource,也可能是绝对路径,类似http://www.hostname.com/somResource,当然啦,做一些判断就OK,最后,规范化以下请求的URI

  3. 请求头信息有HttpHeader类表示,它在创建了之后传给SocketInputStream的readHeader()方法,若是有头信息可以读取,就将其填充。在parseHeaders()方法中,会有一个while循环不断读取HttpReader信息,如果读取到了,就调用request.addHeader(name, value)进行设置,如果没有了那么HttpHeader实例的属性字段nameEnd和nameValue都是0,由于这个InputStream是不支持读写位置的随意移动的,因此读取的方向会一直往下。

  4. Cookie是作为请求头的一部份发送的,字段类似 cookie:username=biu;password=qwert; 解析Tomcat提供的org.apache.catalina.util.RequestUtil类的parseCookieHeader()方法完成,这个方法放回一个Cookie[],每一个元素对于cookie中分号的一个字段。具体就是在上面的那个while循环中加一个if条件判断语句来处理

  5. 解析字段其实不是在这一步就完成的。而是在用户自定义的Servlet中调用getParameter(), getParameterMap(), getParameterNames(), getParameterValues()之后才进行的。这样有一个好处就是,减少解析参数带来的延迟,提高响应速度。参数值需要解析一次,而且也只会解析一次,同时不允许程序员去修改。比如说ParameterMap类,它是一个HashMap,利用一个boolean属性lock来限制修改操作。简单的示例如下:

public final class ParameterMap extends HashMap{        private boolean locked = false;        /* 一系列构造函数 */    public ParameterMap(){        super();    }        /* 比如说下面这个方法 */    public Object put(Object key, Object value){        if(locked)            throw new IllegalStateException(sm.getString("parameterMap.locked"));        return super.put(key, value);    }    }

那么是如何控制只解析一次的呢?原因在parseParameters()方法中也有一个boolean字段parsed,当解析完成,参数会存储到对象变量parameters中,

if(parsed) return;

然后这个方法内部会创建一个名为result的ParameterMap变量,将其指向遍历parameters,若paramters==null,则会创建一个新的对象;接着就打开那个ParameterMap的锁了,setLocked(false);然后检查编码,就可以进行解析工作了,别忘了最后还有setLocked(true);

一个简单的Servlet容器就是初步这样~

转载于:https://my.oschina.net/zjh92119/blog/203672

你可能感兴趣的文章
部运输服务司“两学一做”关注城市智慧交通系统建设
查看>>
立澜光伏项目提交虚假材料被叫停发电
查看>>
Junit在MyEclipse上怎么用?
查看>>
QGraphicsItem如何使用信号/槽
查看>>
《计算机科学导论》一第2章
查看>>
微软被评为全球第二大影响力公司
查看>>
《Excel 职场手册:260招菜鸟变达人》一第 8 招 怎样在多张工作表录入相同的数据——创建工作组...
查看>>
《C语言及程序设计》实践项目——用break和continue改变流程
查看>>
The total number of locks exceeds the lock table size错误(已纠正)
查看>>
maven2完全使用手册
查看>>
SQL应用与开发:(一)导论和环境
查看>>
简单封装quartz实现任务调度的配置和管理
查看>>
Android Matrix详解
查看>>
JVM 堆栈区域数据存放流程
查看>>
【MyBatis框架】配置文件-resultMap总结
查看>>
JSP生成验证码
查看>>
浏览器的窗口位置和大小
查看>>
Path实现常见toolbar点击弹出菜单效果
查看>>
介绍Spring Cloud微服务架构的核心特性
查看>>
剥开比原看代码(六):比原是如何把请求区块数据的信息发出去的
查看>>