剖析 Tomcat
一、Web服务器(超文本传输协议HTTP服务器)如何工作?
Web服务器使用HTTP与其客户端(通常是Browser)进行通信。
基于Java的Web服务器会使用两个重要的类: java.net.Socket类和java.net.ServerSocket类,并通过发送HTTP
消息进行通信。
二、HTTP(HyperText Transfer Protocol)
HTTP允许Web服务器和浏览器通过Internet发送并接受数据,HTTP是一种基于“请求-响应”的半双工协议。应用Case:
客户端请求一个文件,服务器对请求进行响应。 HTTP使用可靠的TCP连接,TCP协议默认使用TCP 80端口。
HTTP应用中,都是由客户端发起请求的,服务器不能主动跟客户端建立连接。
1.1.1 HTTP 请求
Request = Request-Line ; Method SP Request-URI SP HTTP-Version CRLF
; Get www.baidu.com HTTP/1.1 *(( general-header ; Date, Connection, Cache-Control等等 | request-header ; Accept, Accept-CharSet, If-Match 等等 | entity-header ) CRLF) ; Allow, Expires, Last-Modified 等等 CRLF ; Carriage Return/LineFeed, 回车/换行 [ message-body ] ; Section 4.3
1.1.2 HTTP 响应
Response = Status-Line ; HTTP-Version SP Status-Code SP Reason-Phrase CRLF
; HTTP/1.1 200 OK *(( general-header ; 同上 Request 中 | response-header ; Accept-Ranges, Etag, Server 等等 | entity-header ) CRLF) ; 同上 Request 中 CRLF [ message-body ] ; Section 7.2
1.2.1 Socket 类
套接字是网络连接的端点。套接字使应用程序可以从网络中读取数据,向网络中写入数据。不同计算机上的两个应用程序
可以通过连接发送或者接受字节流。从一个应用程序像另外一个应用程序发送消息,需要知道目标应用程序中的套接字的
IP地址和端口号。 Java中, 套接字由 java.net.Socket表示。
1.2.2 ServerSocket 类
Socket类表示一个客户端套接字,即当你想要连接到远程服务器应用程序时创建的套接字。但如果你想要实现一个服务器
应用程序,你需要另一种方法,因为服务器必须随时待命,他并不知道客户端应用程序什么时候发起连接。正因为这种需求
需要使用java.net.ServerSocket 类,这是服务器套接字的实现。
ServerSocket 类和 Socket 类并不相同。服务器套接字要等待来自客户端的连接请求。当服务器套接字收到了连接请求后
它会创建一个Socket实例来处理与客户端的通信
小结:
三、Servlet容器
Servlet容器是用来处理请求servlet资源, 并为Web客户端填充response对象的模块。当socket接到请求后, 判断需要servlet
处理还是只是请求静态资源, 需要servlet处理的话, 加载对应的servlet类, 调用servlet的service()处理请求。简单的servlet容
器就可以分离请求的监听和处理。Servlet编程会使用到 javax.servlet 和 javax.servlet.http 这两个包里的接口和类。
Servlet接口声明了5个方法:
public void init(ServiceConfig config) throws ServletException
public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException
public void destory()
public ServletConfig getServletConfig()
public String getServletInfo()
* init(),service(),destory()和Servlet的声明周期相关。当实例化某个servlet类后,servlet容器会调用其init()方法进行初始化。
servlet容器只会调用一次这个方法,调用后就可以执行service(). servlet在接受任何请求之前,必须经过正确初始化。
* 当请求到达后,servlet容器载入相应的servlet类, 调用这个servlet的service(), servletRequest和servletResponse 对象作为参数
传入. servletRequest对象包含了HTTP请求的信息, ServletResponse对象封装servlet的响应信息。
* servlet实例从服务中移除前, servlet容器会调用destory(). 一般当servlet容器关闭或servlet容器要释放内存时才会移除servlet实例
destory()让servlet对象清理自身持有的资源,如内存、文件句柄和线程等
四、连接器(connector)
简单的servlet就可以分离请求的监听和处理。为了增强功能, 用更好的方式创建request和response对象,分离出来一个模块:连接器。
连接器解析HTTP请求头, 获取请求头、cookie、请求参数/值等信息, 填充HttpRequest实例并提供HttpResponse实例。
HttpConnector类实现了java.lang.Runnable, 它可以专用自己的线程。当启动应用程序时, 创建HttpConnector的一个实例并执行
它的run()方法。
连接器处理请求的三个步骤:
*解析连接(parseConnection):从socket中获取Internet地址,端口号, 检查是否使用了代理
*解析请求(parseRequest) :
*解析请求头(parseHeaders):循环读取所有的HTTP请求信息
五、载入器
servlet容器需要实现一个自定义的载入器来加载servlet类, 而不能完全信任正在运行的servlet类。如果仅仅是使用系统类的载入器载入
某个servlet类所使用的全部类, 那么servlet就能访问所有的类, 包括当前运行的Java虚拟机中环境变量CLASSPATH指明的路径下的所有
的类和库。servlet应该只允许载入WEB-INF/classes目录及其子目录下的类和部署的(WEB-INF/lib目录下)的类
Tomcat 中实现自定义载入器的另外一个原因是为了提供自动重载的功能。当WEB-INF/classes或部署的的类发生变化时, Web应用程序
会重新载入这些类。Tomcat的类载入器会用一个额外的线程不断地检查servlet类和其他类文件的时间戳。
六、Session管理
servlet实例可以通过调用HttpServletRequest的getSession()来获取一个Session对象, Session对象有唯一的标识符Id,根据上次使用
时间来判断对象的有效性, 对象的有效性可以设置或重置。
Session管理器将其所管理的Session对象存放在内存里, Tomcat里, 也可以对Session对象进行持久化, 存储到文件存储器或者数据库中。
注: 本文参考了《深入理解Tomcat工作原理》、HTTP协议等