`
java-boy
  • 浏览: 245080 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

(转)TOMCAT源码分析(消息处理)

    博客分类:
  • Java
阅读更多

本文转自:http://www.dev-share.com/java/99953page2.html

0:前言
我们知道了tomcat的整体框架了, 也明白了里面都有些什么组件, 以及各个组件是干什么用的了。

http://www.csdn.net/Develop/read_article.asp?id=27225

我想,接下来我们应该去了解一下 tomcat 是如何处理jsp和servlet请求的。

1. 我们以一个具体的例子,来跟踪TOMCAT,看看它是如何把Request一层一层地递交给下一个容器,并最后交给Wrapper来处理的。

以http://localhost:8080/web/login.jsp为例子

(以下例子,都是以tomcat4 源码为参考)

这篇心得主要分为3个部分: 前期, 中期, 和末期。

前期:讲解了在浏览器里面输入一个URL,是怎么被tomcat抓住的。

中期:讲解了被tomcat抓住后,又是怎么在各个容器里面穿梭, 最后到达最后的处理地点。

末期:讲解到达最后的处理地点后,又是怎么具体处理的。

2、 前期 Request的born.

在这里我先简单讲一下request这个东西。

我们先看着这个URL:http://localhost:8080/web/login.jsp 它是动用了8080端口来进行socket通讯的。

我们知道, 通过

InputStream in = socket.getInputStream() 和

OutputStream out = socket.getOutputStream()

就可以实现消息的来来往往了。

但是如果把Stream给应用层看,显然操作起来不方便。

所以,在tomcat 的Connector里面, socket被封装成了Request和Response这两个对象。

我们可以简单地把Request看成管发到服务器来的数据,把Response看成想发出服务器的数据。

但是这样又有其他问题了啊? Request这个对象是把socket封装起来了, 但是他提供的又东西太多了。

诸如Request.getAuthorization(), Request.getSocket()。 像Authorization这种东西开发人员拿来基本上用不太着,而像socket这种东西,暴露给开发人员又有潜在的危险。 而且啊, 在Servlet Specification里面标准的通信类是ServletRequest和HttpServletRequest,而非这个Request类。 So, So, So. Tomcat必须得捣持捣持Request才行。 最后tomcat选择了使用捣持模式(应该叫适配器模式)来解决这个问题。它把org.apache.catalina.Request 捣持成了 org.apache.coyote.tomcat4.CoyoteRequest。 而CoyoteRequest又实现了ServletRequest和HttpServletRequest 这两种接口。 这样就提供给开发人员需要且刚刚需要的方法了。

ok, 让我们在 tomcat的顶层容器 - StandardEngin 的invoke()方法这里设置一个断点, 然后访问

http://localhost:8080/web/login.jsp, 我们来看看在前期都会路过哪些地方:

1. run(): 536, java.lang.Thread, Thread.java

CurrentThread

2. run():666, org.apache.tomcat.util.threads.ThreadPool$ControlRunnable, ThreadPool.java

ThreadPool

3. runIt():589, org.apache.tomcat.util.net.TcpWorkerThread, PoolTcpEndpoint.java

ThreadWorker

4. processConnection(): 549

org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler, Http11Protocol.java

http protocol parser

5. Process(): 781, org.apache.coyote.http11.Http11Processor, Http11Processor.java

http request processor

6. service(): 193, org.apache.coyote.tomcat4.CoyoteAdapter,CoyoteAdapter.java

adapter

7. invoke(): 995, org.apache.catalina.core.ContainerBase, ContainerBase.java

StandardEngin

1. 主线程

2. 启动线程池.

3. 调出线程池里面空闲的工作线程。

4. 把8080端口传过来由httpd协议封装的数据,解析成Request和Response对象。

5. 使用Http11Processor来处理request

6. 在Http11Processor里面, 又会call CoyoteAdapter来进行适配处理,把Request适配成实现了ServletRequest和HttpServletRequest接口的CoyoteRequest.

7. 到了这里,前期的去毛拔皮工作就基本上搞定,可以交给StandardEngin 做核心的处理工作了。

3. 中期。 在各个容器间的穿梭。

Request在各个容器里面的穿梭大致是这样一种方式:

每个容器里面都有一个管道(pipline), 专门用来传送Request用的。

管道里面又有好几个阀门(valve), 专门用来过滤Request用的。

在管道的低部通常都会放上一个默认的阀们。 这个阀们至少会做一件事情,就是把Request交给子容器。

让我们来想象一下:

当一个Request进入一个容器后, 它就在管道里面流动,波罗~ 波罗~ 波罗~ 地穿过各个阀门。在流到最后一个阀门的时候,吧唧~ 那个该死的阀门就把它扔给了子容器。 然后又开始 波罗~ 波罗~ 波罗~ ... 吧唧~.... 波罗~ 波罗~ 波罗~ ....吧唧~....

就是通过这种方式, Request 走完了所有的容器。( 感觉有点像消化系统,最后一个地方有点像那里~ )

OK, 让我们具体看看都有些什么容器, 各个容器里面又都有些什么阀门,这些阀们都对我们的Request做了些什么吧:

3.1 StandardEngin 的pipeline里面放的是:StandardEnginValve

在这里,VALVE做了三件事:

1. 验证传递过来的request是不是httpservletRequest.

2 验证传递过来的 request 是否携带了host header信息.

3 选择相应的host去处理它。(一般我们都只有一个host:localhost,也就是127.0.0.1)。

到了这个地方,我们的request就已经完成了在Engin这个部分的历史使命,通向前途未卜的下一站: host了。

3.2 StandardHost 的pipline里面放的是: StandardHostValve

1. 验证传递过来的request是不是httpservletRequest.

2. 根据Request来确定哪个Context来处理。

Context其实就是webapp,比如http://localhost:8080/web/login.jsp

这里web就是Context罗!

3. 既然确定了是哪个Context了,那么就应该把那个Context的classloader付给当前线程了。

Thread.currentThread().setContextClassLoader(context.getLoader().getClassLoader());

这样request就只看得见指定的context下面的classes啊, jar啊这些,而看不见tomcat本身的类,什么Engin啊, Valve啊。不然还得了啊!

4. 既然request到了这里了,看来用户是准备访问web这个web app了,咋们得更新一下这个用户的session不是! Ok , 就由manager更新一下用户的session信息

5. 交给具体的Context 容器去继续处理Request.

6. Context处理完毕了,把classloader还回来。

3.3 StandardContext 的pipline里面放的是: StandardContextValve

1. 验证传递过来的request是不是httpservletRequest.

2. 如果request意图不轨,想要访问/meta-inf, /web-inf这些目录下的东西,呵呵,没有用D!

3. 这个时候就会根据Request到底是Servlet,还是jsp,还是静态资源来决定到底用哪种Wrapper来处理这个Reqeust了。

4. 一旦决定了到底用哪种Wrapper,OK,交给那个Wrapper处理。

4. 末期。 不同的需求是怎么处理的.

StandardWrapper

之前对Wrapper没有做过讲解,其实它是这样一种东西。

我们在处理Request的时候,可以分成3种。

处理静态的: org.apache.catalina.servlets.DefaultServlet

处理jsp的:org.apache.jasper.servlet.JspServlet

处理servlet的:org.apache.catalina.servlets.InvokerServlet

不同的request就用这3种不同的servlet去处理。

Wrapper就是对它们的一种简单的封装,有了Wrapper后,我们就可以轻松地拦截每次的Request。也可以容易地调用servlet的init()和destroy()方法, 便于管理嘛!

具体情况是这么滴:

如果request是找jsp文件,StandardWrapper里面就会封装一个org.apache.jasper.servlet.JspServlet去处理它。

如果request是找 静态资源 ,StandardWrapper里面就会封装一个org.apache.jasper.servlet.DefaultServlet 去处理它。

如果request是找servlet ,StandardWrapper里面就会封装一个org.apache.jasper.servlet.InvokerServlet 去处理它。

StandardWrapper同样也是容器,既然是容器, 那么里面一定留了一个管道给request去穿,管道低部肯定也有一个阀门(注1),用来做最后一道拦截工作.

在这最底部的阀门里,其实就主要做了两件事:

一是启动过滤器,让request在N个过滤器里面筛一通,如果OK! 那就PASS。 否则就跳到其他地方去了。

二是servlet.service((HttpServletRequest) request,(HttpServletResponse) response); 这个方法.

如果是 JspServlet, 那么先把jsp文件编译成servlet_xxx, 再invoke servlet_xxx的servie()方法。

如果是 DefaultServlet, 就直接找到静态资源,取出内容, 发送出去。

如果是 InvokerServlet, 就调用那个具体的servlet的service()方法。

ok! 完毕。

注1: StandardWrapper 里面的阀门是最后一道关口了。 如果这个阀门欲意把request交给StandardWrapper 的子容器处理。 对不起, 在设计考虑的时候, Wrapper就被考虑成最末的一个容器, 压根儿就不会给Wrapper添加子容器的机会! 如果硬是要调用addChild(), 立马抛出IllegalArgumentException!

参考:

<http://jakarta.apache.org/tomcat/>
<http://www.onjava.com/pub/a/onjava/2003/05/14/java_webserver.html>
分享到:
评论

相关推荐

    「Tomcat源码剖析」.pdf

    Tomcat源码剖析 : 整体架构 层层分析 源码解析 架构分析 (Http服务器功能:Socket通信(TCP/IP)、解析Http报文 Servlet容器功能:有很多Servlet(自带系统级Servlet+自定义Servlet),Servlet处理具体的业务逻辑...

    我的tomcat7源码手撕过程

    Tomcat初始化流程分析,Tomcat启动流程分析 Tomcat处理一次请求过程分析 servlet初始化流程

    https原理及tomcat配置https方法

    https原理及tomcat配置https方法;SSL加密传输;请求路径https://...;客户端需安装证书...

    apache-tomcat-8.5.50-src.zip

    Tomcat启动流程分析 组件的生命周期管理 用Lifecycle管理启动、停止、关闭 Lifecycle接口预览 几个核心方法 Server中的init方法示例 为啥StandardServer没有init方法 LifecycleBase中的init与...

    SpringMVC源码分析.md

    Spring的源码分析 在分析SpringMVC源码之前我想先回顾一下JavaWeb的知识.JavaWeb的核心是Servlet,一个Servlet对应一个URL, 每次一个Http请求访问,那么对应URL的Servlet就会调用service方法处理。 其实这里我是对...

    apache-tomcat-8.0.32

    在手写Spring源码的过程中会摘取整体框架中的核心逻辑,简化代码实现过程,保留核心功能,例如:IOC, AOP、 Bean生命周期、上下文、作用域、资源处理等内容实现。适合人群:具备一定编程基础,工作1-3年的研发人能学到什么...

    分析Tomcat的工作原理

    SpringBoot 就像一条巨蟒,慢慢缠绕着我们,使我们麻痹。不得不承认,使用了 SpringBoot 确实提高了工作...但是,清楚 Tomcat 的工作原理和处理请求流程和分析 Spring 框架源码一样的重要。至少面试官特别喜欢问这些底

    java8集合源码分析-memobook:备忘录

    集合源码分析 开发基础 设计模式 配套代码: 算法与数据结构 配套代码: 配套代码: http DevOps git gitlab maven docker 详细安装过程 框架 Spring Mybatis SpringMVC SpringBoot Spring Security Shiro Swagger-...

    大厂学院SVIP十门合集|完结无秘

    02设计模式与框架源码分析 03JVM与GC调优 04JUC并发编程与源码分析 05拥抱云原生 06分布式存储极致性能Redis6 07微服务框架核心源码深度解析 08RPC框架核心源码深度解析 09大数据与人工智能 10监控专题 技术...

    SpringBoot框架开发详解(李兴华)源码

    在本课程之中将为读者完整的分析SpringBoot的运行机制、Tomcat配置部署处理、thymeleaf页面处理框架、文件上传的使用,同时讲解了SpringBoot与消息服务整合、MyBatis整合、邮件整合、Shiro整合、Redis整合处理操作...

    JAVA上百实例源码以及开源项目源代码

     Message-Driven Bean EJB实例源代码,演示一个接收购物订单的消息驱动Bean,处理这个订单同时通过e-mail的形式  //给客户发一个感谢消息,消息驱动Bean必须实现两个接口MessageDrivenBean和MessageListener  在...

    个人博客系统源码及论文

    第2章 系统分析 2.1 系统功能需求 2.1.1 前台 2.1.2 后台 2.2 系统流程 第3章 系统设计 3.1 系统B/S结构 3.2 数据库设计 3.2.1 数据库名称 3.2.2 数据库设计 3.2.3 数据表设计 3.2.4 数据库脚本 第4章 系统...

    JAVA上百实例源码以及开源项目

     Message-Driven Bean EJB实例源代码,演示一个接收购物订单的消息驱动Bean,处理这个订单同时通过e-mail的形式  //给客户发一个感谢消息,消息驱动Bean必须实现两个接口MessageDrivenBean和MessageListener  在...

    某果学院 微服务分布式事物解决方案

    5、消息发送一致性的异常流程处理 6、常规MQ队列消息的处理流程和特点 7、消息重复发送问题及业务接口的幂等性设计 8、可靠消息最终一致性方案1(本地消息服务) 9、可靠消息最终一致性方案2(独立消息服务)的设计 ...

    JSp 医院预约挂号系统源码+数据库

    JSp 医院预约挂号系统源码+数据库。 医院在线预约挂号系统 jsp+mysql+maven 挂号预约系统 选题背景 现有某医院想要提升患者挂号管理水平,打算引入一套挂号预约管理系统。 功能需求 挂号预约系统主要包括基础数据...

    基于SSM的面向学生成绩分析系统(源码+部署说明+演示视频+源码介绍).zip

    基于SSM(Spring、Spring MVC 和 MyBatis)的面向学生成绩分析系统是一款功能强大的Java Web应用程序,旨在帮助学校、教师和学生更好地管理和分析学生的成绩数据。本项目提供了完整的源码、部署说明、演示视频以及源码...

    Spring Boot实战与原理分析视频课程包含14-18

    Spring Boot实战与原理分析视频课程包含14-18,本视频教程为网络整理,如有侵权,请联系删除。谢谢 Spring Boot实战与原理分析视频课程 课程目录: 1 Spring Boot概述与课程概要介绍20:33 2 Spring4 快速入门59:56...

    学籍信息管理系统(附源码、数据库文件、设计文档)

    附源码、数据库文件、设计文档、需求分析、MVC模式解读,WEB动态网站开发;HTML语言;CSS样式;JAVASCRIPT脚本语言;XML脚本技术;MySql数据库;Servlet 、JSP技术;JAVA后台处理;Tomcat服务器;JavaBean等技术的...

    【spring-boot-seckill分布式秒杀系统 v1.0】从0到1构建的java秒杀系统源码+安装说明

    4、异步、异步、异步,分析并识别出可以异步处理的逻辑,比如日志,缩短系统响应时间。 5、主备、主备、主备,如果有条件做好主备容灾方案也是非常有必要的(参考某年锤子的活动被攻击)。 6、最后,为了支撑更高的...

    基于SSH开发的crm客户关系管理系统(完整源码)

    特别说明:该系统采用SSH开发,不熟悉SSH的朋友...4、统计报表:客户贡献分析,客户构成分析,客户服务分析,客户流失分析; 5、基础数据:数据字典管理,查询产品信息,查询库存; 6、权限管理:用户管理,角色管理。

Global site tag (gtag.js) - Google Analytics