Tomcat学习笔记其一
写在前面
以下笔记来自于观看某老师关于Tomcat的讲解视频。因为水平有限和记录原因,笔记可能漏洞百出并杂乱无章。只能说一切仅供参考。
一句谚语
我们常听到一句话“Tomcat是一个Servlet容器”
那么如何理解这句话呢?
Web项目中通常都会有Servlet,而Tomcat只认Servlet。
用Java的形式翻译翻译Tomcat,就有了如下的类:
class Tomcat{
Connection conector; // 请求处理
List<Servlet> servlets; // Servlet池
}
那么什么是Servlet呢?
Servlet说白了就是一种规范。
Servlet == server + applet
其中applet是java里一种古老的技术,表示用户可以用java语言写一个程序,而这个程序运行在浏览器上,就是运行在客户端上的程序。
综上所述,Servlet就是运行在服务端上的程序。
看一段源码
protected void doGet(HttpServletRequset req, HttpServletResponse resp) throws IOException{
resp.getWriter().println("Hello,World");
}
以上代码是某服务应用的doGet方法。我们发现其中的参数是接口类型的。
那么问题来了,是谁来实现这个接口的呢?这个实现类的实例是哪来的呢?
——是Tomcat实现这个接口。
我们来理一下流程:
用户在浏览器上提交数据->浏览器把请求发送给Tomcat服务器->Tomcat把数据封装为Request对象->tomcat.doGet(Requset 对象)
这里留一个issue,因为tomcat.doGet调用的其实是RequestFacade对象。
RequestFacad与Tomcat的门面模式
Tomcat源码里,实现接口的最重要的两个类是:Request类和RequestFacade类。
Facade代表的就是门面的意思。门面是对外的。
Request表示请求,是Tomcat里非常非常核心的类。而Request中有一些东西是Tomcat自己的,Tomcat不想把它们对外开放。
于是就有了RequestFacade类。
RequestFacade对象得到Request中的部分数据,同时把必要信息隐藏起来,让外界看不到。
如此做法一来保护了Tomcat本身,二来更符合Servlet规范。外界少了干扰信息,也就能更加清楚调用请求了。
再回到上面的issue,就明白服务程序调用的请求对象其实是隐藏了Tomcat私密信息的RequestFacade。
细说容器
回到那句话“Tomcat是一个Servlet容器”。
将这句话进行进一步解释,其实是如下的层次结构:
Servlet->Wrapper->Context->Host->Engine
这是一个大型套娃现场。
Wrapper是Servlet的容器,Context是Wrapper的容器,Host是Context的容器,Engine是Wrapper的容器。
Context容器,Host虚拟地址,Engine主机。
在这里重点讲Wrapper。
如果没有Wrapper,因为并发,所有的请求线程将公用一个Servlet实例。
有了Wrapper后每个线程单独有一个Servlet实例。
Wrapper把众多的Servlet放到Servlet池里。然后Context处理Wrapper的Servlet池。
套娃的结构图如下:
管道与阀门
从套娃结构图我们可以发现,每一层容器都有Pipeline管道。
那么Pipeline是干嘛的呢?
Tomcat接收到请求后,请求会以Request对象的形式在管道里向下一层流。
而管道里有很多阀门Value,Request对象每每流经一个阀门,就会触发相应的事件。比如执行某某日志的记录。
在最后的Wrapper层,管道里的Request对象变成了RequestFacade对象,然后RequestFacad对象被交与Servlet来进行服务程序的调用。
还有个Issue
回到最上面的doGet例子。其实Tomcat没有直接调用Servlet里的方法,或者说Tomcat不是直接调用doGet方法。而是调用了Servlet的Service方法。
Service方法是Servlet规范里的。它让Tomcat不必纠结于如何调用与调用哪个的问题。
可以这么说,不是Tomcat调用了服务的具体方法,而是Tomcat调用了服务的服务总管方法,服务总管再调用了具体方法。