欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Tomcat6.0源码学习--架构概述 博客分类: Tomcat 源码研究 Tomcat应用服务器ServletApache浏览器

程序员文章站 2024-02-26 12:06:16
...

Tomcat6 是最新版本的 web 容器,其支持最新版本的 servlet2.5 jsp2.1 。而且 Tomcat6 架构也是经过重新设计优化过的,所以我们有必要分析一下它的架构过程。显然,这是一个通过阅读 Tomcat 的源代码及相关文档,演绎架构的过程。或许有人会说,这不是放马后炮吗?!!但我觉得这是自我进步的一个必经步骤,先模仿之,然后才能超越之,毕竟我本凡人。

Tomcat 的架构总的来说是分层次的、可插拔的组件架构。分层次是指构成 Tomcat 的组件不是同一级别的,上层组件可以包含子组件,各个组件有其功能范围,当一个组件停止服务时,不会影响上层组件的服务。可插拔是指对于组件的添加和删除并不影响服务器的运行。那么为了达到可插拔的组件架构,分层次的组件架构必成为基础。

对于任何服务器,即使最简单的实现,从面向对象设计( OOD )的角度来说,我们都有必要将“服务器”这个概念抽象出来,为什么呢?因为只有有了这个概念,才能谈服务器的实例,服务器的功能等等其它概念,此之谓“皮之不存,毛将焉附”。赶巧( 其实是我的想法恰好撞上人家的想法 ), Tomcat 也将“服务器”抽象为 java 接口 org.apache.catalina.Server ,显然 Server 应该就是最最顶层的组件了。

有了 Server 这个抽象,很自然的,我们希望它能够提供对 servlet jsp 支持的功能。但是我们发现这个概念太大了,我们还需再细化。所以别急,我们还有一些事情要解决。服务器要提供服务就必须能够启动,当然也应该能够停止吧,也就是说服务器应该是有生命的,在启动时初始化必要的资源,而在停止时将其其销毁掉。好吧,我们把这个也抽象出来,叫做生命周期接口, tomcat 实现为 org.apache.catalina.Lifecycle. 如上所述我们知道 Lifecycle 需要完成的工作了。

public void start () throws LifecycleException;

public void stop() throws LifecycleException;

接下来我们分析服务器如何来处理客户端的请求,一般的我们会在浏览器中输入如下格式的请求, http://192.168.8.221:8080/explorer/loginInit.do 。对于服务器来说,要想处理这个请求,就必须监听指定的端口 8080 ,当有 TCP 的请求包来时,建立 Socket 连接,分析并解析之,然后给客户端返回响应。在这个过程中,我们发现,其实包含了俩个功能点,即监听并接受请求和处理请求。那么我们能否将这俩个功能给抽象出来呢? Tomcat 告诉我们,可以。是的, Tomcat 将“监听并接收请求”抽象为 org.apache.catalina.connector.Connector 类,负责接受请求;将“处理请求”抽象为“容器” org.apache.catalina.Container ,负责处理 Connector 传递过来的请求。

Ok, 到此,我们分析构建的简单服务器模型出来了, Server Connector 组件和 Container 组件结合提供 web 服务。

 

Tomcat6.0源码学习--架构概述
            
    
    博客分类: Tomcat 源码研究 Tomcat应用服务器ServletApache浏览器

2

有了这个模型后,要实现一个简单的 Server 已经很简单了,但是在实现 Container 时,我们还是要做很多事情,如当来请求,我们怎么知道该请求对应得虚拟主机,以及请求的那个应用,应该交给那个 servlet 对象来处理?这样看来, Container 还是太大了,需要细化。根据 Servlet 规范,我们知道, servlet 属于某个应用,且有上下文环境, Container 要根据应用上下文环境初始化 servlet ,然后根据 servlet 映射调用 servlet service 方法。在这里“应用上下文环境”的概念很重要, Tomcat 将其抽象为 org.apache.catalina.Context Context 继承了 Container 接口。对于虚拟主机, Tomcat 将其抽象为 org.apache.catalina.Host Host 继承了 Container 接口。

好了,有了这些概念,我们再回顾一下请求的处理过程:浏览器发出请求, Connector 接受请求,将请求交由 Container 处理, Container 查找请求对应的 Host 并将请求传递给它, Host 拿到请求后查找相应的应用上下文环境,准备 servlet 环境并调用 service 方法。

现在,我们的服务器模型变成了如图 3 所示了。

 

Tomcat6.0源码学习--架构概述
            
    
    博客分类: Tomcat 源码研究 Tomcat应用服务器ServletApache浏览器

3

但是在 Tomcat 的实现体系中还有一个 Engine 的接口, Engine 也继承了 Container 接口,那么这个接口什么用呢?设计 Engine 的目的有俩个目的,一,当希望使用拦截器查看(过滤或预处理)每个请求时, Engine 是个很好的拦截点。二,当希望多个虚拟 Host 共享一个 Http Connector 时, Engine 是个很好的门面。所以, Engine 接口是作为* Container 组件来设计的,其作用相当于一个 Container 的门面。有了 Engine ,请求的处理过程变为:浏览器发出请求, Connector 接受请求,将请求交由 Container (这里是 Engine )处理, Container Engine 来担当)查找请求对应的 Host 并将请求传递给它, Host 拿到请求后查找相应的应用上下文环境,准备 servlet 环境并调用 service 方法。再看看服务器的模型,如图 4.

 

Tomcat6.0源码学习--架构概述
            
    
    博客分类: Tomcat 源码研究 Tomcat应用服务器ServletApache浏览器

4

到目前,我们碰到的组件类型有 Connector Container ,其实,这也就是 Tomcat 的核心组件。如图 4 ,一组 Connector 和一个 Container 有机的组合在一起构成 Server ,就可以提供服务了,对于 Tomcat 来说,主要是提供 Servlet 服务,那么也就是说 Tomcat 服务器也可以提供其它服务了?是的, Tomcat 将“一组 Connector 和一个 Container 有机的组合”抽象为“服务”接口 org.apache.catalina.Service ,然而,这些服务实例彼此独立,仅仅共享 JVM 的基础设施,如系统类路径。

进一步的,我们得到了服务器的框架模型,如图 5.

 

Tomcat6.0源码学习--架构概述
            
    
    博客分类: Tomcat 源码研究 Tomcat应用服务器ServletApache浏览器

5

    由图 5 ,我们知道,对于 Tomcat 服务器来说,除了 Server 代表它自己以外,其它组件都是功能组件,都有其职责范围。 Service 为最顶层的组件,可以添加 Connector Container 组件。 Engine Container 的最顶层组件,可以添加 Host 组件,但不能添加父组件。 Host 组件的父组件是 Engine Host 下面包含有 Context 组件。

    接下来看看标准的 Tomcat 体系结构,如图 6.

 

Tomcat6.0源码学习--架构概述
            
    
    博客分类: Tomcat 源码研究 Tomcat应用服务器ServletApache浏览器

6

比较图 5 和图 6. 我们发现,还有很多辅助组件没有抽象出来。当然,随着需求的一步步加深,我的分析也会一步步深入,这些个组件也会慢慢浮出水面。