tomcat源码解读(一)

tomcat源码解读(一)

什么是 tomcat ?

Tomcat是由Apache软件基金会下属的Jakarta项目开发的一个Servlet容器,按照Sun Microsystems提供的技术
规范,实现了对Servlet和JavaServer Page(JSP)的支持,并提供了作为Web服务器的一些特有功能,如Tomcat
管理和控制平台、安全域管理和Tomcat阀等。由于Tomcat本身也内含了一个HTTP服务器,它也可以被视作一个单独
的Web服务器。但是,不能将Tomcat和Apache HTTP服务器混淆,Apache HTTP服务器是一个用C语言实现的
HTTPWeb服务器;这两个HTTP web server不是捆绑在一起的。Apache Tomcat包含了一个配置管理工具,也可
以通过编辑XML格式的配置文件来进行配置。

简而言之:tomcat是一个接受 http 请求并解析 http 请求并反馈客户端的一个应用程序.

tomcat 可以说是 sun Servlet 的一个官方参考实现, 因为 tomcat 刚开始就是 sun 开发的,后来捐献给了 apache 基金会.

在我们理解 tomcat 之前, 我们得了解一下tomcat 所实现的 Servlet 是什么?

那要从互联网大潮兴起开始讲起, 我们知道, 网页不止有静态的还有动态的, 而在刚开始的时候, 常见的实现动态网页的技术就是 CGI, 但是作为 Java 的发明人, SUN|肯定要搞一个超级大风头, 让整个世界一下子认识了 Java, 不过很快悲催的发现 Applet 其实用途不大, 眼看着互联网开始流行, 一定要搭上千载难逢的快车啊.

于是, Servlet 就诞生了, Servlet 其实就是 SUN 为了让 Java 能实现动态的可交互的网页, 从而进入 web 编程的领域而定义的一套标准.

这套标准是这么说的: 你想用 Java 开发动态网页, 可以定义一个自己的" Servlet", 但一定要实现我的 HTTPServlet 接口, 然后重载 doGet(), doPost()方法. 用户从流浪器 GET 的时候, 调用 doGet 方法, 从流浪器向服务器发送表单数据的时候, 调用 doPost 方法, 如果你想访问用户从浏览器传递过来的参数, 用 HttpServletRequest 对象就好了, 里面有 getParameter, getQueryString 方法, 如果你处理完了, 想向浏览器返回数据, 用 HttpServletResponse 对象调用 getPrintWriter 方法就可以输出数据了.

如果你想实现一个购物车, 需要 session, 很简单, 从 HttpServletRequest 调用 getSession 方法就可以了.

Servlet 是如何工作的
servlet 是一个复杂的系统, 但是他有三个基本任务, 对每个请求, servlet 容器会为其完成以下3个操作:

  (1) 创建一个 Request 对象, 用可能会在调用的 Servlet 中使用到的信息填充该 Request 对象, 如参数, 头, cookie, 查询字符串, URI 等, Request 对象是 javax.servlet.ServletRequest 接口或 javax.servlet.ServletRequest 接口的一个实例.
  (2) 创建一个调用 Servlet 的 Response 对象, 用来向 Web 客户端发送响应. response 对象是 javax.servlet.http.ServletResponse 接口或 javax.servlet.ServletResponse 接口的一个实例;
  (3) 调用 Servlet 的 service 方法, 将 request 对象和 response 对象作为参数传入, Servlet 从 request 对象中读取信息, 并通过 response 对象发送响应信息.

你写了一个" Servlet", 接下来要运行, 你就发现没法通过 java 直接运行了, 你需要一个能够运行 Servlet 的容器, 这个容器 Sun 最早实现了一个, 叫 Java Web Server, 1999年捐给了 Apache Software foundation, 就改名叫 Tomcat. 这就是 Tomcat 的由来.

所以, Tomcat 就是一个 Servlet 容器, 能接收用户从浏览器发来的请求, 然后转发给 Servlet 处理, 把处理完的响应数据发回浏览器.

但是 Servlet 输出 Html, 还是采用了老的 CGI 方式 , 是一句一句输出, 所以,编写和修改 html 非常不方便, 于是, Java Server Pages(JSP) 就来救急了, JSP 并没有增加任何本质上不能用 Servlet 实现的功能, 实际上 JSP 在运行之前, 需要先编译成 Servlet, 然后才执行的.

但是, 在 JSP 中编写静态 HTML 更加方便, 不必再用 println 语句来输出每一行HTML 代码, 更重要的是, 借助内容和外观的分离,页面制作中不同性质的任务可以方便的分开: 比如, 有页面设计者进行 HTML 设计, 同时流出供 Java 程序插入动态内容的空间.

Tomcat 能运行 Servlet, 当然能运行 JSP 了.

既然是 Web 服务器, tomcat 除了能运行 Servlet 和 JSP 之外, 也能像 Apache/nginx 一样, 支持静态 html, 图片, 文档的访问, 只是性能差一点,在实际的应用中, 一般是 Apache/nginx 作为负载均衡服务器和静态资源服务器放在最前端, 后面是 tomcat 组成的集群.

如果用户请求的是静态资源, nginx 直接搞定, 如果是动态资源(如xxx.jsp), nginx 就会按照一定的算法转发的某个 tomcat 上, 达到负载均衡的目的.

Tomcat 是如何设计的? 有哪些所谓的组件?

首先可以通过下面图来进行简要的说明
在这里插入图片描述
Tomcat 整体的框架层次:4个层次, 其中 Connector 和 Container 是最重要的.
Server 和 Service
Connector
  HTTP
  AJP (apache 私有协议,用于tomcat和apache静态服务器通信)
Container
  Engine
  Host
  Context
  Wrapper
Component
  Manager (管理器)
  logger (日志管理)
  loader (载入器)
  pipeline (管道)
  valve (管道中的阀)

注意: Server是整个Tomcat组件的容器,包含一个或多个Service。 Service:Service是包含Connector和Container的集合,Service用适当的Connector接收用户的请求,再发给相应的Container来处理。

从这张图中可以看到,Tomcat的核心组件就两个Connector和Container(后面还有详细说明),多个
Connector+一个Container构成一个Service,Service就是对外提供服务的组件,有了Service组件Tomcat就
可以对外提供服务了,但是光有服务还不行,还得有环境让你提供服务才行,所以最外层的Server就为Service提
供了生存的土壤。那么这些个组件到底是干嘛用的呢?Connector是一个连接器,主要负责接收请求并把请求交给
Container,Container就是一个容器,主要装的是具体处理请求的组件。Service主要是为了关联Container与
Connector,一个单独的Container或者一个单独的Connector都不能完整处理一个请求,只有两个结合在一起
才能完成一个请求的处理。Server这是负责管理Service集合,从图中我们看到一个Tomcat可以提供多种服务,
那么这些Serice就是由Server来管理的,具体的工作包括:对外提供一个接口访问Service,对内维护Service集
合,维护Service集合又包括管理Service的生命周期、寻找一个请求的Service、结束一个Service等

Connector 组件:

Tomcat都是在容器里面处理问题的, 而容器又到哪里去取得输入信息呢? Connector就是专干这个的。 他会把
从socket传递过来的数据, 封装成Request, 传递给容器来处理。 通常我们会用到两种Connector,一种叫http 
connectoer, 用来传递http需求的。 另一种叫AJP, 在我们整合apache与tomcat工作的时候,apache与
tomcat之间就是通过这个协议来互动的。 (说到apache与tomcat的整合工作, 通常我们的目的是为了让apache
获取静态资源, 而让tomcat来解析动态的jsp或者servlet。)

总的来说,Connector就是解析Http或Ajp请求的。

Container 组件:

我们刚刚看到, 容器从大到小分别是 Engine, Host, Context, Wrapper, 从左到右每个容器都是一对多关系, 
也就是说, Engine 容器可以有多个 Host 容器, Host 容器可以有多个 Context 容器. Context 容器可以有
多个 Wrapper 容器.


我们来看看每个组件的解释:
     Container:可以理解为处理某类型请求的容器,处理的方式一般为把处理请求的处理器包装为Valve(阀门)
对象,并按一定顺序放入类型为Pipeline(管道)的管道里。Container有多种子类型:Engine、Host、Context
和Wrapper,这几种子类型Container依次包含,处理不同粒度的请求。另外Container里包含一些基础服务,如
Loader、Manager和Realm。
     Engine:Engine包含Host和Context,接到请求后仍给相应的Host在相应的Context里处理。
	 Host:就是我们所理解的虚拟主机。
	 Context:就是我们所部属的具体Web应用的上下文,每个请求都在是相应的上下文里处理的。
	 Wrapper:Wrapper是针对每个Servlet的Container,每个Servlet都有相应的Wrapper来管理。 可以
看出Server、Service、Connector、Container、Engine、Host、Context和Wrapper这些核心组件的作用
范围是逐层递减,并逐层包含。

下面就是些被Container所用的基础组件:
	 Loader:是被Container用来载入各种所需的Class。
	 Manager:是被Container用来管理Session池。
	 Realm:是用来处理安全里授权与认证。

Component 组件:

  需求被传递到了容器里面, 在合适的时候, 会传递给下一个容器处理。而容器里面又盛装着各种各样的组件, 我们可以理解为提供各种各样的增值服务。比如:

		manager: 当一个容器里面装了manager组件后,这个容器就支持session管理了, 事实上在tomcat
里面的session管理, 就是靠的在context里面装的manager component.

		logger: 当一个容器里面装了logger组件后, 这个容器里所发生的事情, 就被该组件记录下来, 我们
通常会在logs/ 这个目录下看见catalina_log.time.txt 以及localhost.time.txt和
localhost_examples_log.time.txt。 这就是因为我们分别为:engin, host以及context(examples)
这三个容器安装了logger组件, 这也是默认安装, 又叫做标配 .

		loader: loader这个组件通常只会给我们的context容器使用,loader是用来启动context以及
管理这个context的classloader用的。

		pipline: pipeline是这样一个东西,使用的责任链模式. 当一个容器决定了要把从上级传递过来的需
求交给子容器的时候, 他就把这个需求放进容器的管道(pipeline)里面去。 而需求傻呼呼得在管道里面流动的时
候, 就会被管道里面的各个阀门拦截下来。 比如管道里面放了两个阀门。 第一个阀门叫做
“access_allow_vavle”, 也就是说需求流过来的时候,它会看这个需求是哪个IP过来的, 如果这个IP已经在黑
名单里面了,sure, 杀! 第二个阀门叫做“defaul_access_valve”它会做例行的检查, 如果通过的话,OK, 
把需求传递给当前容器的子容器。 就是通过这种方式, 需求就在各个容器里面传递,流动, 最后抵达目的地的了。
		valve: 就是上面所说的阀门。
		
Tomcat里面大概就是这么些东西, 我们可以简单地这么理解tomcat的框架,它是一种自上而下, 容器里又包含
子容器的这样一种结构。

换个角度再来看看 Tomcat 的总体架构:

  • 面向组件架构
  • 基于JMX
  • 事件侦听

面向组件架构 tomcat代码看似很庞大,但从结构上看却很清晰和简单,它主要由一堆组件组成,如Server、Service、Connector等,并基于JMX管理这些组件,另外实现以上接口的组件也实现了代表生存期的接口Lifecycle,使其组件履行固定的生存期,在其整个生存期的过程中通过事件侦听LifecycleEvent实现扩展。Tomcat的核心类图如下所示:

在这里插入图片描述
上面我们已经对每个类的功能进行了一些描述.包括 Catalina 类和 Server 类的作用, Service 类是如何关联 Connector 和 Container 的. 还有各个容器是上面关系. 包括容器中数据是如何从从管道( pipeline) 中传递, 还有一些组件, 比如类载入器, 管理器, 安全主体( realm);

基于JMX Tomcat会为每个组件进行注册过程,通过Registry管理起来,而Registry是基于JMX来实现的,因此在看组件的init和start过程实际上就是初始化MBean和触发MBean的start方法,会大量看到形如: Registry.getRegistry(null, null).invoke(mbeans, “init”, false); Registry.getRegistry(null, null).invoke(mbeans, “start”, false); 这样的代码,这实际上就是通过JMX管理各种组件的行为和生命期。

那么, 什么是 JMX 呢?

JMX 即 Java Management Extensions(JMX 规范), 是用来对 tomcat 进行管理的. tomcat 中的实现是
commons modeler 库, Catalina 使用这个库来见哈编写托管 Bean 的工作. 托管 Bean 就是用来管理
Catalina 中其他对象的 Bean.

事件侦听(观察者模式/事件驱动) 各个组件在其生命期中会有各种各样行为,而这些行为都有触发相应的事件,Tomcat就是通过侦听这些时间达到对这些行为进行扩展的目的。在看组件的init和start过程中会看到大量如: lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);这样的代码,这就是对某一类型事件的触发,如果你想在其中加入自己的行为,就只用注册相应类型的事件即可。











转载的是这位大佬的莫那一鲁道.
为了能让自己的系列更加完全,如果有侵权,请联系我

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值