`

tomcat源码阅读

 
阅读更多
tomcat7源码  build eclipse
http://tomcat.apache.org/tomcat-7.0-doc/building.html

http://ss1.javaeye.com/category/85155
http://speed847.javaeye.com/blog/search?page=2&query=tomcat
http://asialee.javaeye.com/?page=1


http://hi.baidu.com/macula7/blog/category/Tomcat/index/1 全部译文


https://www.ibm.com/developerworks/cn/java/j-lo-tomcat1/  Tomcat 设计模式分析
http://www.ibm.com/developerworks/cn/java/j-lo-tomcat2/ Tomcat 系统架构与设计模式,第 2 部分: 设计模式分析
https://www.ibm.com/developerworks/cn/java/j-lo-servlet/Servlet 工作原理解析
http://www.ibm.com/developerworks/cn/java/j-lo-jetty/?cmp=dwskl&cpb=dw&ct=dwcon& Jetty 的工作原理以及与 Tomcat 的比较
http://www.ibm.com/developerworks/cn/java/l-from-tomact/index.html  从Tomcat中得到更多-Tomcat的源码分析
http://blog.csdn.net/wangchengsi/article/details/2973012  Tomcat连接器:Coyote框架

http://www.infoq.com/cn/articles/zh-tomcat-http-request-1
http://he-wen.iteye.com/blog/846829

连接器  HttpConnector
处理器  HttpProcessor
容器    Container

http://blog.csdn.net/wangchengsi/article/details/2966847 别人的阅读心得

system.in.read()方法的作用是从键盘读出一个字符,然后返回它的Unicode码。按下Enter结束输入


/---------------------------
目录
3章、连接器 35
4章、tomcat的默认连接器  58
5章、容器 76
6章、生命周期94
7章、日志系统 108
8章、加载器   118
9章、session管理 133
10章、Security
11章、StandardWrapper
12章、StandardContext
13章、Host and Engine
14章、Server and Service
15章、Digester
16章、Shutdown Hook

3/
Catalina 中有两个主要的模块:连接器和容器
-----------------------------------------
4/
4.1Tomcat 连接器是一个可以插入 servlet 容器的独立模块,已经存在相当多的连接器了,包 括Coyote, mod_jk, mod_jk2和mod_webapp
它等待前来的HTTP 请求,创建request
和 response 对象,然后把 request 和 response 对象传递给容器。连接器是通过调用接口
org.apache.catalina.Container 的 invoke 方法来传递 request 和 response 对象的

4.2在 invoke方法里边,容器加载 servlet,调用它的 service 方法,管理会话,记录出错日

志等等

4.3Tomcat连接器必须实现org.apache.catalina.Connector接口。在这个接口的众多方法中,
最重要的是 getContainer,setContainer, createRequest和 createResponse。

yxw
1、HttpConnector  initialize()  调用一个ServeSocket的工厂方法创建ServerSocket
2、HttpConnector  的start()  创建了一个指定大小的HttpProcessor对象池
同时调用了HttpProcessor的start方法,HttpProcessor实现线程接口,也就是执行run()方法,run()调用await(),因为available = false,被wait()在while内等待自己被notifyAll
3、HttpConnector实现了线程接口,start被调用,也就是执行run()方法,run方法内 while循环, 等待(serverSocket.accept())http请求进来
4、请求进来,HttpProcessor processor = createProcessor();从对象池中返回,
执行HttpProcessor 的processor.assign(socket);并把socket传进去,
assign方法内
while (available) {}被跳过  #此时available=false
available = true;
5、notifyAll();唤醒第2步中的HttpProcessor实例的await()中被阻断的部分继续执行,await()返回socket,HttpProcessor的run方法内process(socket);
await()返回socket的同时
available = false;
notifyAll();
此时第4步assign(socket)方法内while (available) {}依然能被跳过,也就又可以接受新的http请求了

6、第5步内HttpProcessor的run方法内process(socket);执行完毕connector.recycle(this);  HttpProcessor实例被放回连接器的实例池内

7、在第1步创建HttpConnector创建一个container
把容器set给连接器,在处理器的process方法中调用了容器的invoke方法,在容器的invoke方法中调用了servlet.service()


-------------------------
容器
所有的容器类都扩展自抽象类ContainerBase
1、
org.apache.catalina.Container接口定义了容器的形式,
有四种容器:Engine(引擎), Host(主机), Context(上下文), 和 Wrapper(包装器)
·        Engine:表示整个Catalina的servlet引擎
·        Host:表示一个拥有数个上下文的虚拟主机
·        Context:表示一个Web应用,一个context包含一个或多个wrapper
·        Wrapper:表示一个独立的servlet
一个容器可以有一个或多个低层次上的子容器

传递一个Container实例给Connector对象的setContainer方法,然后Connector对象就可以使用container 的invoke方法

2、Container
一个容器还包含一系列的部分如Lodder、 Loggee、 Manager、 Realm和Resources。

更有意思的是Container接口被设计成Tomcat管理员可以通过server.xml文件配置来决定其工作方式的模式。它通过一个pipeline(流水线)和一系列的阀门来实现
org.apache.catalina中四个相关的接口:Pipeline, Valve, ValveContext, 和 Contained。
Pipeline  流水线接口
Value  阀门接口
ValueContext 阀门上下文接口
Contained

一个pipeline包含了改容器要唤醒的所有任务。每一个阀门表示了一个特定的
任务。一个容器的流水线有一个基本的阀门,但是你可以添加任意你想要添加的
阀门。阀门的数目定义为添加的阀门的个数(不包括基本阀门)

如果你已经理解了servlet过滤器,那么流水线和它的阀门的工作方式不难想象。
一个流水线就像一个过滤链,每一个阀门像一个过滤器。跟过滤器一样,一个阀
门可以操作传递给它的request和response 方法。让一个阀门完成了处理,则
进一步处理流水线中的下一个阀门,基本阀门总是在最后才被调用。
一个容器可以有一个流水线。当容器的invoke方法被调用的时候,容器将会处
理流水线中的阀门,并一个接一个的处理,直到所有的阀门都被处理完毕

流水线必须保证说要添加给它的阀门必须被调用一次,流水线通过创建一
个ValveContext接口的实例来实现它。ValveContext是流水线的的内部类,这
样ValveContext就可以访问流水线中所有的成员。ValveContext中最重要的方
法是invokeNext方法:

3、Wrapper(包装器)
org.apache.catalina.Wrapper接口表示了一个包装器。一个包装器是表示一个
独立servlet定义的容器。包装器继承了Container接口,并且添加了几个方法。
包装器的实现类负责管理其下层servlet的生命中期,包括servlet的
init,service,和destroy方法。由于包装器是最底层的容器,所以不可以将子
容器添加给它。如果addChild方法被调用的时候会产生
IllegalArgumantException异常。
包装器接口中重要方法有allocate和load方法。allocate方法负责定位该包
装器表示的servlet的实例。Allocate方法必须考虑一个servlet是否实现了
avax.servlet.SingleThreadModel接口,该部分内容将会在 11 章中进行讨论。
Load方法负责load和初始化servlet的实例。


Mapper 接口
如何使用一个包含两个包装器的上下文来包装两个
servlet类。当有多于一个得包装器的时候,需要一个 map 来处理这些子容器,
对于特殊的请求可以使用特殊的子容器来处理

####################
容器的invoke()方法调用流水线接口pipeline的invoke方法
流水线通过创建一 个ValveContext 接口的实例来实现它。ValveContext 是流水线的的内部类,这
样ValveContext 就可以访问流水线中所有的成员。ValveContext 中最重要的方
法是 invokeNext方法:
public void invokeNext(Request request, Response response)
  throws IOException, ServletException

流水线、阀门的设计很是精巧
1、HttpConnector connector = new HttpConnector();
    Wrapper wrapper = new SimpleWrapper();
new连接器,
new包装器时,
  public SimpleWrapper() {
    pipeline.setBasic(new SimpleWrapperValve());
  }
2、SimplePipeline pipeline = new SimplePipeline(this);
流水线Pipeline是包装器的属性类,new流水线时把包装器自己this当做一个容器传递进去
3、pipeline.setBasic(new SimpleWrapperValve());
把基本阀门SimpleWrapperValve  setBasic()进去
  public void setBasic(Valve valve) {
    this.basic = valve;
    ((Contained) valve).setContainer(container);
  }
此处的value其实是SimpleWrapperValve  ,container是SimpleWrapper

4、set阀门
    ((Pipeline) wrapper).addValve(valve1);
    ((Pipeline) wrapper).addValve(valve2);
connector.setContainer(wrapper);  把包装器当做容器set给连接器
connector.initialize(); 连接器
connector.start();
处理器process(Socket socket)方法中调用容器的invoke方法,这一部分就是默认连接器的处理,请同上面的描述
   connector.getContainer().invoke(request, response);
5、也就是调用SimpleWrapper这个包装器的invoke方法
  public void invoke(Request request, Response response)
    throws IOException, ServletException {
    pipeline.invoke(request, response);
  }
里面调用了SimplePipeline的invoke(request, response);方法
6、SimplePipeline的invoke(request, response)内
  public void invoke(Request request, Response response)
    throws IOException, ServletException {
    // Invoke the first Valve in this pipeline for this request
    (new SimplePipelineValveContext()).invokeNext(request, response);
  }
SimplePipelineValveContext 是SimplePipeline的内部类
SimplePipelineValveContext  实现ValveContext接口(阀门上下文接口)

6、调用SimplePipelineValveContext的invokeNext(request, response)
    public void invokeNext(Request request, Response response)
      throws IOException, ServletException {
      int subscript = stage;
      stage = stage + 1;
      // Invoke the requested Valve for the current request thread
      if (subscript < valves.length) {
        valves[subscript].invoke(request, response, this);
      }
      else if ((subscript == valves.length) && (basic != null)) {
        basic.invoke(request, response, this);
      }
      else {
        throw new ServletException("No valve");
      }
    }
  } // end of inner class
if else 分别调用 3步设置的基本阀门  4步设置的日志、ip阀门
调用阀门的invoke(request, response, this);时把自己SimplePipelineValveContext传进去
再基本阀门中的调用SimplePipelineValveContext的invokeNext()方法形成类似递归的一个流水线调用
或者说是栈

###
可以使用 setBasic方法来分配一个基本阀门给流水线,getBasic方法会
得到基本阀门。最后被唤醒的基本阀门,负责处理request和回复response。


###
context 接口
一个 context在容器中表示一个web 应用。一个 context通常含有一个或多个包
装器作为其子容器。

重要的方法包括addWrapper, createWrapper 等方法

上下文 容器

--------------------------------------------
6、生命周期
一个实现了Lifecycle接口的组件同是会触发一个或多个下列事件:
BEFORE_START_EVENT, START_EVENT, AFTER_START_EVENT, BEFORE_STOP_EVENT,
STOP_EVENT, and AFTER_STOP_EVENT。当组件被启动的时候前三个事件会被触发,
而组件停止的时候会触发后边三个事件。另外,如果一个组件可以触发事件,那
么必须存在相应的监听器来对触发的事件作出回应。监听器使用
org.apache.catalina.LifecycleListener来表示

Lifecycle 中最重要的方法是start和 stop方法。一个组件提供了这些方法的
实现,所以它的父组件可以通过这些方法来启动和停止他们。另外3个方法
addLifecycleListener, findLifecycleListeners, 和
removeLifecycleListener 事跟监听器相关的类。组件的监听器对组件可能触发
的时间 “感兴趣”,当一个事件被触发的时候,相应监听器会被通知。一个
Lifecycle 实例可以触发使用静态最终字符串定义的六个事件。

LifeCycleEvent类 表示一个生命周期事件
LifeCycleListener接口 表示一个生命周期监听器
该接口中,只有一个方法 lifecycleEvent,该方法在事件触发的时候唤醒对
其 “感兴趣”的监听器

LifecycleSupport 类

  connector.initialize();
      ((Lifecycle) connector).start();
      ((Lifecycle) context).start();

第5章时 只需要连接器start();
现在需要容器也start()
1、new SimpleContextLifecycleListener()
LifecycleListener listener = new SimpleContextLifecycleListener();
    ((Lifecycle) context).addLifecycleListener(listener);
2、容器的addLifecycleListener(listener);
  public void addLifecycleListener(LifecycleListener listener) {
    lifecycle.addLifecycleListener(listener);
  }

3、容器实现了Lifecycle 生命周期接口
((Lifecycle) context).start();#显示调用

----------------------------------------
日志系统 
FileLogger  implements Lifecycle 实现了 生命周期接口


------------------------------
类加载器
一个 servlet容器需要一个定制的容器,而不是简单的使用系统的加
载器。如果像前面章节中那样使用系统的加载器来加载 servlet和其他需要的类,
这样 servlet就可以进入Java虚拟机CLASSPATH 环境下面的任何类和类库,这
会带来安全隐患。Servlet 只允许访问WEB-INF/目录及其子目录下面的类以及部
署在WEB-INF/lib 目录下的类库。

Tomcat 需要一个自己的加载器的另一个原因是它需要支持在WEB-INF/classes
或者是WEB-INF/lib 目录被改变的时候会重新加载。Tomcat 的加载器实现中使
用一个单独的线程来检查 servlet和支持类文件的时间戳。要支持类的自动加载
功能,一个加载器类必须实现org.apache.catalina.loader.Reloader接口

1、其中bootstrap类加载器用于引导 JVM,一旦调用java.exe程序,bootstrap
类加载器就开始工作。因此,它必须使用本地代码实现,然后加载 JVM 需要的类
到函数中。另外,它还负责加载所有的Java 核心类,例如 java.lang和 java.io
包。另外bootstrap类加载器还会查找核心类库如 rt.jar、i18n.jar等,这些
类库根据 JVM和操作系统来查找。

extension类加载器负责加载标准扩展目录下面的类。这样就可以使得编写程序
变得简单,只需把JAR 文件拷贝到扩展目录下面即可,类加载器会自动的在下面
查找。不同的供应商提供的扩展类库是不同的,Sun 公司的JVM 的标准扩展目录
是/jdk/jre/lib/ext。

system加载器是默认的加载器,它在环境变量CLASSPATH 目录下面查找相应的
类。

这样,JVM 使用哪个类加载器?答案在于委派模型(delegation model)
委派模型对于安全性是非常重要的


---------------------------------------------------------
13 Host和Engine
engine 表示了整个catalina 的servlet 引擎。engine 是处于最顶层的container。被添加到engine 的子
container 通常是org.apache.catalina.Host 或org.apache.catalina.Context。tomcat 默认是使用engine 的


-----------------------------------------------------------
14 Server与Service

在前面的章节中,已经说明了connector 和container 是如何工作的.在8080 端口上,只能有一个connector
服务于http 请求

org.apache.catalina.Server 接口表示了整个catalina 的servlet 引擎,囊括了所有的组件。server 使用一种
优雅的方法来启动/停止整个系统,不需要对connector 和container 分别启动/关闭
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics