一.连接器
1. 什么是连接器?
所谓连接器就是负责创建一个服务器套接字实例,并根据该实例等待客户端的请求,然后提供HttpServlerRequest和HttpServletResponse实例。
在接下的代码中,这个连接器将会解析HTTP请求头,使servlet实例能够获取请求头,cookie、和请求参数/值等信息。
2.错误信息类
对于Tomcat中出现的错误信息也需要进行配置和说明,就好比如说javasrc中也有相应的错误信息处理的类
Tomcat错误信息类放在StringManager类中。例如,对于系统管理员根据Tomcat的错误日志消息定位到发生异常的位置。对于servlet程序员来说,在抛出的每个javax.servlet.servletException异常中,Tomcat都会发送一条特殊的错误消息。
Tomcat处理错误消息的方法是将错误消息存在分布在不同包的中properties文件中,便于读取和编辑。
当包中的某个类需要在其保内的properties文件中查找错误消息时,它会先获取对应的StringManager实例。若对于每一个类需要查找错误消息都要实例化一个StringManager实例,显然开销是很大。基于节约成本的思想,StringManager类被设置成单例类,即其中的构造方法是私有的,仅能调用getManager()方法获取StringManger类的实例,并且其传递的参数是包名。
比如《深入剖析Tomcat》书中ex03.pyrmont.connector.http包下,含有3个properties文件,StringManager实例会根据运行该程序的服务器语言环境选择使用何种语言的properties文件.
这是StringManager的构造函数,是私有的。
这是StringManager类的getManager()的方法,用于获取StringManager实例。
通过传递包名获取StringManger实例
调用StringManager类的getString()方法,向其传递错误信息
查看properties文件中相关字串,可以得知“httpProcessor.parseHeaders.colon”错误将产生“Invalid HTTP header format”错误消息提示。
二.使用连接器的Servlet程序
现在开始介绍使用连接器的Servlet程序,本程序分为三个模块。
1.启动模块.启动模块只有一个类(Bootstrap.java),这个类负责启动程序。
2.连接器模块.连接器模块可以分成5个部分
连接器及其支持类(HttpConnector.java和HttpProcessor.java)
表示HTTP请求的类(HttpRequest.java)及其支持类(HttpHeader.java和HttpRequestLine.java)
表示HTTP响应的类(HttpResponse.java)及其支持类()
外观类(HttpRequestFacade.java和HttpResponseFacade.java)
资源类(Constants.java)
3.核心模块.核心模块包括两个类,servletProcessor类和StaticResourceProcessor类
1. 本Servlet程序将使用一下包名,类名
l ex03.pyrmont.connector
Ø RequestStream.java
Ø ResponseStream.java
Ø ResponseWriter.java
l ex03.pyrmont.connector.http
Ø HttpConnector.java--连接器类
Ø HttpProcessor.java--连接器支持类
Ø HttpRequest.java--解析请求类
Ø HttpRequestFacade.java--解析请求类的外观类
Ø HttpResponse.java--响应类
Ø HttpResponseFacade.java--响应类的外观类
Ø Constants.java--资源类
Ø SocketInputStream.java--套接字输入流类
Ø HttpHeader.java--解析请求头类
Ø HttpRequestLine.java--解析请求行类
l ex03.pyrmont.startup
Ø Bootstrap.java--启动类
l ex03.pyrmont
Ø ServletProcessor.java
Ø StaticResourceProcessor.java
l org.apache.catalina.util
Ø StringManager.java
Ø RequestUtil.java
Ø ParameterMap.java
2. UML类图
3. 启动模块
本程序通过Bootstrap类作为启动类,通过实例化HttpConnector对象,在调用其start()方法启动整个服务器程序。
4. 连接器模块
连接器模块是整个程序最为复杂的模块,在上一个Servlet程序中,HttpServer类负责等待HTTP请求,并创建Request和Response对象。在这个程序改变思路,通过使用连接器来等待HTTP请求,即通过HttpConnector类等待HTTP请求,创建Request和Response对象工作由HttpProcessor类。
在接下的程序中,不同于上一个Servlet程序,HTTP请求对象使用HttpRequest类表示,HttpRequest类实现了javax.servlet.http.HttpServletRequest接口。HTTP响应对象使用HttpResponse类表示,HttpResponse类实现了java.servlet.http.HttpSeveltResponse接口。
HttpRequest对象会转型为HttpServletRequest对象,然后作为参数传递给service()方法。使用连接器时不知道并调用的servlet会使用诸如:“URI”,“查询字符串”,“参数”,“Cookie”,“其他一些请求头信息”的值。因此每个HttpRequest对象必须正确获取和设置以上的值。
HttpResponse对象会转型为HttpServletResponse对象,该类会向浏览器输出字节流,通过使用PrintWriter对象。
本Servlet程序的连接器将使用SocketInputStream类,该类继承自InputStream类,从输入流读取字节流。SocketInputStream类是InputStream类的包装类,可以通过调用套接字的getInputStream()方法获取实例。这个类有两个重要的方法,其一是readRequestLine()方法,读取HTTP请求的第一行内容,该内容包括,请求方法,URI,和HTTP协议版信息,返回的是HttpRequestLine的是实例。其二是readHeader()方法,使用该方法将返回HTTP请求信息的一对名字/值信息,并返回HttpHeader实例。注意,使用readRequestLine()方法应该注意,必须在readHeader()方法前使用。因为,套接字的输入流处理字节流是从第1个字节读取到最后一个字节(并不能从后往前读),因此必须使用readRequestLine()方法。
1. HttpConnector类--连接器类。实现了Runnable接口