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

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

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

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

publicvoidstart()throwsLifecycleException;

publicvoidstop()throwsLifecycleException;

接下来我们分析服务器如何来处理客户端的请求,一般的我们会在浏览器中输入如下格式的请求,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,到此,我们分析构建的简单服务器模型出来了,ServerConnector组件和Container组件结合提供web服务。

2

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

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

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

3

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

4

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

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

5

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

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

6

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

以上转自:http://blog.163.com/haizai219@126/blog/static/4441255520098841540516/

-------------------------------------------------------------------------------------------------------------------------------------

Tomcat从5.5版本开始,支持以下四种Connector的配置分别为 NIO, HTTP, POOL, NIOP:

<Connector port="8081" protocol="org.apache.coyote.http11.Http11NioProtocol" connectionTimeout="20000" redirectPort="8443"/>

<Connector port="8081" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443"/>

<Connector executor="tomcatThreadPool"port="8081" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />

<Connector executor="tomcatThreadPool" port="8081" protocol="org.apache.coyote.http11.Http11NioProtocol" connectionTimeout="20000" redirectPort="8443" />

NetworkClient

-->Socket-->PlainSocketImpl的native void socketConnect(InetAddress paramInetAddress, int paramInt1, int paramInt2)

NetworkServer

带main方法的ServerSocket

HttpURLConnection

-->HttpClient extends NetworkClient

tomcat 如何通过jmx loader 、digester架构

一、目录结构:

apache-tomcat-5.5.23\server\lib

apache-tomcat-5.5.23\common\lib

conf\context.xml

<Context><WatchedResource>WEB-INF/web.xml</WatchedResource></Context>

conf\web.xml

这个里面的加载

jasper-compiler.jar负责把index_jsp转化成index_jsp.servlet,(当首次访问该jsp时)

apache-tomcat-5.5.23\work\Catalina\localhost\myservlet\org\apache\jsp\index_jsp

二、

conf\server.xml元素结构

<Server port="8005" shutdown="SHUTDOWN">

<Listener className="org.apache.catalina.mbeans.ServerLifecycleListener"/>

<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener"/>

<Service name="Catalina">

//1、端口。将port=80,进入本地服务时就不用敲80在末尾了(浏览器默认),这样当安装了IIS服务(80端口)时,tomcat无法启动(它是serversocket)。

<Connector URIEncoding="utf-8" connectionTimeout="20000" port="8080" protocol="org.apache.coyote.http11.Http11NioProtocol" redirectPort="8443" useBodyEncodingForURI="true"/>

<Engine defaultHost="localhost" name="Catalina">

<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true" xmlValidation="false" xmlNamespaceAware="false">

<Context docBase="mypushlet" path="/mypushlet" reloadable="true" source="org.eclipse.jst.jee.server:mypushlet"/>

</Host>

</Engine>

</Service>

</Server>

2.虚拟目录:所有的开发程序【JSP、servlet文件】保存在虚拟目录中。

设虚拟目录 "myweb",通过 http://localhost:8080/myweb 访问物理路径 L:\java\JWeb 文件夹里面的内容。设置过程如下:

1.复制 Tomcat6.0\webapps\ROOT 目录下的 WEB-INF 文件夹到 L:\java\JWeb 目录下。

2.打开L:\java\JWeb\WEB-INF 目录下的 web.xml 文件,在 </description> 之后加入:

<!--JSPC servlet mappings start -->

<!--JSPC servlet mappings end -->

3.打开 Tomcat6.0\conf\server.xml 文件,在 <Host> 和 </Host> 之间加入:

<Context path="/myweb" docBase="L:\java\JWeb"></Context>

path="/myweb" 就是虚拟目录的名称

docBase="L:\java\JWeb"> 为物理路径

4.打开 Tomcat6.0\conf\web.xml 文件,找到:

<init-param>

<param-name>listings</param-name>

<param-value>false</param-value>

</init-param>

把false设成true保存,重启Tomcat,现在就可以应用 http://localhost:8080/myweb 虚拟目录了。

1.1 - Server

A Server element represents the entire Catalina servlet container. (Singleton)

1.2 - Service

A Service element represents the combination of one or more Connector components that share a single Engine

Service是这样一个集合:它由一个或者多个Connector组成,以及一个Engine,负责处理所有Connector所获得的客户请求

1.3 - Connector

一个Connector将在某个指定端口上侦听客户请求,并将获得的请求交给Engine来处理,从Engine处获得回应并返回客户。

Coyote Http/1.1 Connector 在端口8080处侦听来自客户browser的http请求

Coyote JK2 Connector 在端口8009处侦听来自其它WebServer(Apache)的servlet/jsp代理请求

1.4 - Engine

An Engine is a Container that represents the entire Catalina servlet engine.

If used, an Engine is always the top level Container in a Catalina.

Engine下可以配置多个虚拟主机Virtual Host,每个虚拟主机都有一个域名。

当Engine获得一个请求时,它把该请求匹配到某个Host上,然后把该请求交给该Host来处理

1.5 - Host

架构:

Server: 其实就是BackGroud程序, 在Tomcat里面的Server的用处是启动和监听服务端事件(诸如重启、关闭等命令。SHUTDOWN)

Service: 一类问题的解决方案。默认使用Tomcat-Standalone 模式的service。既给我们提供解析jsp和servlet的服务, 同时也提供给我们解析静态文本的服务。

Connector:从socket传递过来的数据, 封装成Request, 传递给容器来处理。http、https、ajp(apache与tomcat)三种

Container: 当http connector把需求传递给顶级的container: Engin的时候, 我们的视线就应该移动到Container这个层面来了。

在Container这个层, 我们包含了3种容器: Engin, Host, Context.

Engin: 收到service传递过来的需求, 处理后, 将结果返回给service( service 是通过 connector 这个媒介来和Engin互动的 ).

Host: Engin收到service传递过来的需求后,不会自己处理, 而是交给合适的Host来处理。

Host在这里就是虚拟主机的意思, 通常我们都只会使用一个主机,既“localhost”本地机来处理。

Context: 一个web app,Host接到了从Host传过来的需求后, 也不会自己处理, 而是交给合适的Context来处理。

Compenent: 容器有各种各样的组件, 提供各种各样的增值服务。

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

logger: 当一个容器里面装了logger组件后

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

pipline: 容器间传递并过滤。

2. Tomcat的启动流程: 第一步是装配工作(父容器装上子容器,容器安插进组件)。 第二步是启动工作。

2.3 Catalina.java

1. 使用Digester技术装配tomcat各个容器与组件。

1.1 装配工作的主要内容是安装各个大件。 比如server下有什么样的servcie。 Host会容纳多少个context。 Context都会使用到哪些组件等等。

1.2 同时呢, 在装配工作这一步, 还完成了mbeans的配置工作。 在这里,我简单地但不十分精确地描述一下mbean是什么,干什么用的。

我们自己生成的对象, 自己管理, 天经地义! 但是如果我们创建了对象了, 想让别人来管, 怎么办呢? 我想至少得告诉别人我们都有什么, 以及通过什么方法可以找到 吧! JMX技术给我们提供了一种手段。 JMX里面主要有3种东西。Mbean, agent, connector.

Mbean: 用来映射我们的对象。也许mbean就是我们创建的对象, 也许不是, 但有了它, 就可以引用到我们的对象了。

Agent: 通过它, 就可以找到mbean了。

Connector: 连接Agent的方式。 可以是http的, 也可以是rmi的,还可以直接通过socket。

发生在tomcat 装配过程中的事情: GlobalResourcesLifecycleListener 类的初始化会被触发:

protected static Registry registry = MBeanUtils.createRegistry(); 会运行

MBeanUtils.createRegistry() 会依据/org/apache/catalina/mbeans/mbeans-descriptors.xml这个配置文件创建 mbeans. Ok, 外界就有了条途径访问tomcat中的各个组件了。

2. 为top level 的server 做初始化工作。 实际上就是做通常会配置给service的两条connector.(http, ajp)

3. 从server这个容器开始启动, 点燃整个tomcat.

4. 为server做一个hook程序, 检测当server shutdown的时候, 关闭tomcat的各个容器用。

5. 监听8005端口, 如果发送"SHUTDOWN"(默认培植下字符串)过来, 关闭8005serverSocket。

2.4 启动各个容器

1. Server

触发Server容器启动前(before_start), 启动中(start), 启动后(after_start)3个事件, 并运行相应的事件处理器。

启动Server的子容器:Servcie.

2. Service

启动Service的子容器:Engin

启动Connector

3. Engin

到了Engin这个层次,以及以下级别的容器, Tomcat就使用了比较一致的启动方式了。

首先, 运行各个容器自己特有一些任务

随后, 触发启动前事件

立即, 设置标签,就表示该容器已经启动

接着, 启动容器中的各个组件: loader, logger, manager等等

再接着,启动mapping组件。(注1)

紧跟着,启动子容器。

接下来,启动该容器的管道(pipline)

然后, 触发启动中事件

最后, 触发启动后事件。

Engin大致会这么做, Host大致也会这么做, Context大致还是会这么做。 那么很显然地, 我们需要在这里使用到代码复用的技术。 tomcat在处理这个问题的时候, 漂亮地使用了抽象类来处理。 ContainerBase. 最后使得这部分完成复杂功能的代码显得干净利落, 干练爽快, 实在是令人觉得叹为观止, 细细品来, 直觉如享佳珍, 另人齿颊留香, 留恋往返啊!

Engin的触发启动前事件里, 会激活绑定在Engin上的唯一一个Listener:EnginConfig。

这个EnginConfig类基本上没有做什么事情, 就是把EnginConfig的调试级别设置为和Engin相当。 另外就是输出几行文本, 表示Engin已经配置完毕, 并没有做什么实质性的工作。

注1: mapping组件的用处是, 当一个需求将要从父容器传递到子容器的时候, 而父容器又有多个子容器的话, 那么应该选择哪个子容器来处理需求呢? 这个由mapping 组件来定夺。

4. Host

同Engin一样, 也是调用ContainerBase里面的start()方法, 不过之前做了些自个儿的任务,就是往Host这个容器的通道(pipline)里面, 安装了一个叫做

“org.apache.catalina.valves.ErrorReportValve”的阀门。

这个阀门的用处是这样的: 需求在被Engin传递给Host后, 会继续传递给Context做具体的处理。 这里需求其实就是作为参数传递的Request, Response。 所以在context把需求处理完后, 通常会改动response。 而这个org.apache.catalina.valves.ErrorReportValve的作用就是检察response是否包含错误, 如果有就做相应的处理。

5. Context

到了这里, 就终于轮到了tomcat启动中真正的重头戏,启动Context了。

StandardContext.start() 这个启动Context容器的方法被StandardHost调用.

5.1 webappResources 该context所指向的具体目录

5.2 安装defaultContex, DefaultContext 就是默认Context。 如果我们在一个Host下面安装了DefaultContext,而且defaultContext里面又安装了一个数据库连接池资源的话。 那么其他所有的在该Host下的Context, 都可以直接使用这个数据库连接池, 而不用格外做配置了。

5.3 指定Loader. 通常用默认的org.apache.catalina.loader.WebappLoader这个类。   Loader就是用来指定这个context会用到哪些类啊, 哪些jar包啊这些什么的。

5.4 指定 Manager. 通常使用默认的org.apache.catalina.session. StandardManager 。 Manager是用来管理session的。

其实session的管理也很好实现。 以一种简单的session管理为例。 当需求传递过来的时候, 在Request对象里面有一个sessionId 属性。 OK, 得到这个sessionId后, 我们就可以把它作为map的key,而value我们可以放置一个HashMap. HashMap里边儿, 再放我们想放的东西。

5.5 postWorkDirectory (). Tomcat下面有一个work目录。 我们把临时文件都扔在那儿去。 这个步骤就是在那里创建一个目录。 一般说来会在%CATALINA_HOME%/work/Standalone\localhost\ 这个地方生成一个目录。

5.6 Binding thread。到了这里, 就应该发生 class Loader 互换了。 之前是看得见tomcat下面所有的class和lib. 接下来需要看得见当前context下的class。 所以要设置contextClassLoader, 同时还要把旧的ClassLoader记录下来,因为以后还要用的。

5.7 启动 Loader. 指定这个Context具体要使用哪些classes, 用到哪些jar文件。 如果reloadable设置成了true, 就会启动一个线程来监视classes的变化, 如果有变化就重新启动Context。

5.8 启动logger

5.9 触发安装在它身上的一个监听器。

lifecycle.fireLifecycleEvent(START_EVENT, null);

作为监听器之一,ContextConfig会被启动. ContextConfig就是用来配置web.xml的。 比如这个Context有多少Servlet, 又有多少Filter, 就是在这里给Context装上去的。

5.9.1 defaultConfig. 每个context都得配置 tomcat/conf/web.xml 这个文件。

5.9.2 applicationConfig 配置自己的 WEB-INF/web.xml 文件

5.9.3 validateSecurityRoles 权限验证。 通常我们在访问/admin 或者/manager的时候,需要用户要么是admin的要么是manager的, 才能访问。 而且我们还可以限制那些资源可以访问, 而哪些不能。 都是在这里实现的。

5.9.4 tldScan: 扫描一下, 需要用到哪些标签(tag lab)

5.10 启动 manager

5.11 postWelcomeFiles() 我们通常会用到的3个启动文件的名称:

index.html、index.htm、index.jsp 就被默认地绑在了这个context上

5.12 listenerStart 配置listener

5.13 filterStart 配置 filter

5.14 启动带有<load-on-startup>1</load-on-startup>的Servlet.

顺序是从小到大: 1,2,3… 最后是0

默认情况下, 至少会启动如下3个的Servlet:

org.apache.catalina.servlets.DefaultServlet

处理静态资源的Servlet. 什么图片啊, html啊, css啊, js啊都找他

org.apache.catalina.servlets.InvokerServlet

处理没有做Servlet Mapping的那些Servlet.

org.apache.jasper.servlet.JspServlet

处理JSP文件的.

5.15 标识context已经启动完毕,tomcat启动完毕。

/**

* A <b>Host</b> is a Container that represents a virtual host in the

* Catalina servlet engine.  It is useful in the following types of scenarios:

* <ul>

* <li>You wish to use Interceptors that see every single request processed

*     by this particular virtual host.

* <li>You wish to run Catalina in with a standalone HTTP connector, but still

*     want support for multiple virtual hosts.

* </ul>

* In general, you would not use a Host when deploying Catalina connected

* to a web server (such as Apache), because the Connector will have

* utilized the web server's facilities to determine which Context (or

* perhaps even which Wrapper) should be utilized to process this request.

* <p>

* The parent Container attached to a Host is generally an Engine, but may

* be some other implementation, or may be omitted if it is not necessary.

* <p>

* The child containers attached to a Host are generally implementations

* of Context (representing an individual servlet context).

*/

每个虚拟主机下都可以部署(deploy)一个或者多个Web App,每个Web App对应于一个Context,有一个Context path。

当Host获得一个请求时,将把该请求匹配到某个Context上,然后把该请求交给该Context来处理。

1.6 - Context

一个Context对应于一个Web Application,一个Web Application由一个或者多个Servlet组成。

Context在创建的时候将根据配置文件$CATALINA_HOME/conf/web.xml和$WEBAPP_HOME/WEB-INF/web.xml载入Servlet类。

当Context获得请求时,将在自己的映射表(mapping table)中寻找相匹配的Servlet类,如果找到,则执行该类,获得请求的回应,并返回。

1.7 - 示例

browser发送请求到本机端口8080--> Connector --> Engine --> Host --> Context --> servlet 构造request、response --> Context --> Host --> Engine -- > connector --> browser

public final class Bootstrap{

private static Bootstrap daemon = null;

private Object catalinaDaemon;

protected ClassLoader commonLoader;

protected ClassLoader catalinaLoader;

protected ClassLoader sharedLoader;//Webapp1Loader  Webapp2Loader ...

public Bootstrap(){...}

private void initClassLoaders(){...}

catalinaDaemon = this.catalinaLoader.loadClass("org.apache.catalina.startup.Catalina").newInstance();

public void start()throws Exception{

Method method = this.catalinaDaemon.getClass().getMethod("start", (Class[])null);

method.invoke(this.catalinaDaemon, (Object[])null);

}

}

public class StandardService implements Lifecycle, Service, MBeanRegistration

protected Connector connectors[] = new Connector[0];

protected ArrayList<Executor> executors = new ArrayList<Executor>();

/**

* this holds the most recently added Engine.is generally an instance of Engine

*/

protected Container container = null;

/**

* The lifecycle event support for this component.

*/

private LifecycleSupport lifecycle = new LifecycleSupport(this);

/**

* The <code>Server</code> that owns this Service, if any.

*/

private Server server = null;

/**

* The property change support for this component.

*/

protected PropertyChangeSupport support = new PropertyChangeSupport(this);

public void addConnector(Connector connector) {}

public void addPropertyChangeListener(PropertyChangeListener listener) {}

public void addExecutor(Executor ex) {}

public void addLifecycleListener(LifecycleListener listener) {}

}

//embed [im'bed] 嵌入

public class Embedded  extends StandardServic{

public synchronized void addEngine(Engine engine) {}

}

//启动Tomcat,就生成Catalina实例,server实例????

根据配置文件server.xml,实例化的对象。对象实例化过程中,会做载入webapp,在特定端口等待客户连接等工作。

从server.xml到对象的映射是通过commons-digester.jar包完成的。这个包的一个主要功能就是映射xml到java对象。

public class Catalina extends Embedded {

protected String configFile = "conf/server.xml";

/**

* The application main program.

* @param args Command line arguments

*/

public static void main(String args[]) {

(new Catalina()).process(args);

}

/**

* The instance main program.

* @param args Command line arguments

*/

public void process(String args[]) {

load(args);

start();

}

/**

* Start a new server instance.

*/

public void start() {

((Lifecycle) getServer()).start();

}

protected Digester createStartDigester() {

digester.addObjectCreate("Server",

"org.apache.catalina.core.StandardServer",

"className");

digester.addSetProperties("Server");

digester.addSetNext("Server",

"setServer",

"org.apache.catalina.Server");

digester.addSetNext("Server/GlobalNamingResources",

"setGlobalNamingResources",

"org.apache.catalina.deploy.NamingResources");

digester.addSetNext("Server/Listener",

"addLifecycleListener",

"org.apache.catalina.LifecycleListener");

digester.addSetNext("Server/Service",

"addService",

"org.apache.catalina.Service");

digester.addSetNext("Server/Service/Listener",

"addLifecycleListener",

"org.apache.catalina.LifecycleListener");

digester.addSetNext("Server/Service/Executor",

"addExecutor",

"org.apache.catalina.Executor");

digester.addSetNext("Server/Service/Connector",

"addConnector",

"org.apache.catalina.connector.Connector");

digester.addSetNext("Server/Service/Connector/Listener",

"addLifecycleListener",

"org.apache.catalina.LifecycleListener");

}

}

//available for use(but not required) when deploying and starting Catalina.

public final class StandardServer implements Lifecycle, Server, MBeanRegistration{

public StandardServer() {

ServerFactory.setServer(this);

globalNamingResources = new NamingResources();

globalNamingResources.setContainer(this);

if (isUseNaming()) {

if (namingContextListener == null) {

namingContextListener = new NamingContextListener();

addLifecycleListener(namingContextListener);

}

}

}

private javax.naming.Context globalNamingContext = null;

private NamingResources globalNamingResources = null;

private NamingContextListener namingContextListener = null;

/**

* The port number on which we wait for shutdown commands.

*/

private int port = 8005;

awaitSocket = new ServerSocket(port, 1, InetAddress.getByName("localhost"));

}

public class Connector implements Lifecycle, MBeanRegistration{

protected Service service = null;

/**

* The Container used for processing requests received by this Connector.

*/

protected Container container = null;

/**

* Use "/" as path for session cookies ?

*/

protected boolean emptySessionPath = false;

/**

* The redirect port for non-SSL to SSL redirects.

*/

protected int redirectPort = 443;

/**

* The request scheme that will be set on all requests received through this connector.

*/

protected String scheme = "http";

/**

* Maximum size of a POST which will be automatically parsed by the

* container. 2MB by default.

*/

protected int maxPostSize = 2 * 1024 * 1024;

/**

* Maximum size of a POST which will be saved by the container

* during authentication可信的. 4kB by default

*/

protected int maxSavePostSize = 4 * 1024;

/**

* The background thread.

*/

protected Thread thread = null;

/**

* Coyote Protocol handler class name.

* Defaults to the Coyote HTTP/1.1 protocolHandler.

*/

protected String protocolHandlerClassName =

"org.apache.coyote.http11.Http11Protocol";

/**

* Coyote protocol handler.

*/

protected ProtocolHandler protocolHandler = null;

/**

* Coyote adapter.

*/

protected Adapter adapter = null;

/**

* Mapper.

*/

protected Mapper mapper = new Mapper();

/**

* Mapper listener.

*/

protected MapperListener mapperListener = new MapperListener(mapper, this);

/**

* URI encoding.

*/

protected String URIEncoding = null;

/**

* URI encoding as body.

*/

protected boolean useBodyEncodingForURI = false;

/**

* Set the Coyote protocol which will be used by the connector.

*/

public void setProtocol(String protocol) {

if (AprLifecycleListener.isAprAvailable()) {

if ("HTTP/1.1".equals(protocol)) {

setProtocolHandlerClassName

("org.apache.coyote.http11.Http11AprProtocol");

} else if ("AJP/1.3".equals(protocol)) {

setProtocolHandlerClassName

("org.apache.coyote.ajp.AjpAprProtocol");

} else if (protocol != null) {

setProtocolHandlerClassName(protocol);

} else {

setProtocolHandlerClassName

("org.apache.coyote.http11.Http11AprProtocol");

}

} else {

if ("HTTP/1.1".equals(protocol)) {

setProtocolHandlerClassName

("org.apache.coyote.http11.Http11Protocol");

} else if ("AJP/1.3".equals(protocol)) {

setProtocolHandlerClassName

("org.apache.jk.server.JkCoyoteHandler");

} else if (protocol != null) {

setProtocolHandlerClassName(protocol);

}

}

}

/**

* Create (or allocate) and return a Request object suitable for

* specifying the contents of a Request to the responsible Container.

org.apache.catalina.connector.Request

*/

public Request createRequest() {

Request request = new Request();

request.setConnector(this);

return (request);

}

/**

* Create (or allocate) and return a Response object suitable for

* receiving the contents of a Response from the responsible Container.

*/

public Response createResponse() {

Response response = new Response();

response.setConnector(this);

return (response);

}

// 省略------------------------------------------------------ Lifecycle Methods

// 省略-------------------- JMX registration  --------------------

/**

* Shutdown hook which will perform a clean shutdown of Catalina if needed.

*/

protected class CatalinaShutdownHook extends Thread {

public void run() {

try {

if (getServer() != null) {

Catalina.this.stop();

}

} catch (Throwable ex) {

log.error(sm.getString("catalina.shutdownHookFail"), ex);

} finally {

// If JULI is used, shut JULI down *after* the server shuts down

// so log messages aren't lost

LogManager logManager = LogManager.getLogManager();

if (logManager instanceof ClassLoaderLogManager) {

((ClassLoaderLogManager) logManager).shutdown();

}

}

}

}

}

public interface Engine extends Container {

public String getDefaultHost();

public void setDefaultHost(String defaultHost);

public String getJvmRoute();

public void setJvmRoute(String jvmRouteId);

public Service getService();

public void setService(Service service);

}

public class StandardEngine extends ContainerBase implements Engine{}

public class StandardHost extends ContainerBase implements Host{

/**

* The set of aliases for this Host.

*/

private String[] aliases = new String[0];

private final Object aliasesLock = new Object();

/**

* The application root for this Host.

*/

private String appBase = "webapps";

/**

* The auto deploy flag for this Host.

*/

private boolean autoDeploy = true;

/**

* The Java class name of the default context configuration class

* for deployed web applications.

*/

private String configClass =

"org.apache.catalina.startup.ContextConfig";

/**

* The Java class name of the default Context implementation class for

* deployed web applications.

*/

private String contextClass =

"org.apache.catalina.core.StandardContext";

/**

* Attribute value used to turn on/off XML namespace awarenes.

*/

private boolean xmlNamespaceAware = false;

/**

* Track the class loaders for the child web applications so memory leaks漏洞

* can be detected.

*/

private Map<ClassLoader, String> childClassLoaders =

new WeakHashMap<ClassLoader, String>();

...其他的field省略

}

/**

* Standard implementation of the <b>Context</b> interface.  Each

* child container must be a Wrapper implementation to process the

* requests directed to a particular servlet.

*/

public class StandardContext extends ContainerBase implements Context, Serializable, NotificationEmitter{

/**

* The ServletContext implementation associated with this Context.

*/

protected transient ApplicationContext context = null;

/**

* Compiler classpath to use.

*/

private String compilerClasspath = null;

/**

* Should we attempt to use cookies for session id communication?

*/

private boolean cookies = true;

/**

* Should we allow the <code>ServletContext.getContext()</code> method

* to access the context of other web applications in this server?

*/

private boolean crossContext = false;

/**

* The MIME mappings for this web application, keyed by extension.

*/

private HashMap mimeMappings = new HashMap();

/**

* The servlet mappings for this web application, keyed by

* matching pattern.

*/

private HashMap servletMappings = new HashMap();

/**

* The welcome files for this application.

*/

private String welcomeFiles[] = new String[0];

/**

* Cache object max size in KB.

*/

protected int cacheObjectMaxSize = 512; // 512K

/**

* Cache TTL in ms.

*/

protected int cacheTTL = 5000;

/**

* The domain to use for session cookies. <code>null</code> indicates that

* the domain is controlled by the application.

*/

private String sessionCookieDomain;

/**

* The path to use for session cookies. <code>null</code> indicates that

* the path is controlled by the application.

*/

private String sessionCookiePath;

/**

* The name to use for session cookies. <code>null</code> indicates that

* the name is controlled by the application.

*/

private String sessionCookieName;

}

/**

* Standard implementation of the <b>Wrapper</b> interface that represents

* an individual servlet definition.  No child Containers are allowed, and

* the parent Container must be a Context.

*/

public interface Wrapper extends Container{}

public class StandardWrapper extends ContainerBase implemen ts ServletConfig, Wrapper, NotificationEmitter {

/**

* The (single) initialized instance of this servlet.

*/

protected Servlet instance = null;

/**

* The context-relative URI of the JSP file for this servlet.

*/

protected String jspFile = null;

}

/**

* Standard implementation of <code>ServletContext</code> that represents

* a web application's execution environment.  An instance of this class is

* associated with each instance of <code>StandardContext</code>.

*/

public class ApplicationContext implements ServletContext {

/**

* The Context instance with which we are associated.

*/

private StandardContext context = null;

/**

* Base path.

*/

private String basePath = null;

public String getRealPath(String path) {

File file = new File(basePath, path);

return (file.getAbsolutePath());

}

/**

* Return a <code>RequestDispatcher</code> instance that acts as a

* wrapper for the resource at the given path.  The path must begin

* with a "/" and is interpreted as relative to the current context root.

*

* @param path The path to the desired resource.

*/

public RequestDispatcher getRequestDispatcher(String path) {}

protected StandardContext getContext() {

return this.context;

}

}

/**

* Startup event listener for a <b>Context</b> that configures the properties

* of that Context, and the associated defined servlets.

*/

public class ContextConfig implements LifecycleListener {

/**

* The Context we are associated with.

*/

protected Context context = null;

/**

* The default web application's context file location.

*/

protected String defaultContextXml = null;

/**

* The default web application's deployment descriptor location.

*/

protected String defaultWebXml = null;

}

org.apache.catalina.core.ApplicationHttpRequest

extends javax.servlet.http.HttpServletRequestWrapper

extends javax.servlet.ServletRequestWrapper

//作用类似javaBean

public final class org.apache.coyote.Request{

private int serverPort = -1;

private UDecoder urlDecoder = new UDecoder();

private MimeHeaders headers = new MimeHeaders();

private MessageBytes uriMB = MessageBytes.newInstance();

}

org.apache.catalina.connector.Request implements HttpServletRequest{

protected org.apache.coyote.Request coyoteRequest

public InputStream getStream() {

if (inputStream == null) {

inputStream = new CoyoteInputStream(inputBuffer);

}

return inputStream;

}

protected int readPostBody(byte body[], int len)throws IOException {

int inputLen = getStream().read(body, offset, len - offset);

}

/**

* Return the session associated with this Request, creating one

* if necessary and requested.

*/

public HttpSession getSession(boolean create) {

Session session = doGetSession(create);

if (session != null) {

return session.getSession();

} else {

return null;

}

}

/**

* Change the ID of the session that this request is associated with. There

* are several things that may trigger an ID change. These include moving

* between nodes in a cluster and session fixation prevention during the

* authentication process.

*/

public void changeSessionId(String newSessionId) {...}

protected Session doGetSession(boolean create) {

// Attempt to reuse session id if one was submitted in a cookie

// Do not reuse the session id if it is from a URL, to prevent possible

// phishing attacks

if (connector.getEmptySessionPath()

&& isRequestedSessionIdFromCookie()) {

session = manager.createSession(getRequestedSessionId());

} else {

//createSession最终会调用StandardSession的构造。

session = manager.createSession(null);

}

// Creating a new session cookie based on that session

if ((session != null) && (getContext() != null)

&& getContext().getCookies()) {

String scName = context.getSessionCookieName();

if (scName == null) {

scName = Globals.SESSION_COOKIE_NAME;

}

Cookie cookie = new Cookie(scName, session.getIdInternal());

configureSessionCookie(cookie);

//save到浏览器内存

response.addSessionCookieInternal(cookie, context.getUseHttpOnly());

}

}

/**

* Parse accept-language header value.

*/

protected void parseLocalesHeader(String value) {...}

public String getParameter(String name) {...}

}

Connector通过8080端口连接coyote http1.1,通过8009连接coyote AJP1.3

ServerCookie、Cookies与javax.servlet.http.Cookie的联系?

cookie如何实现的?还有浏览器的。如何获取解析cookie、url重写过的sessionid

/**

*  Server-side cookie representation.

*  Allows recycling and uses MessageBytes as low-level

*  representation ( and thus the byte-> char conversion can be delayed

*  until we know the charset ).

*  Tomcat.core uses this recyclable object to represent cookies,

*  and the facade will convert it to the external representation.

*/

public class org.apache.tomcat.util.http.ServerCookie implements Serializable {...}

/**

* A collection of cookies - reusable and tuned for server side performance.

* Based on RFC2965 ( and 2109 )

*/

public final class org.apache.tomcat.util.http.Cookies {

ServerCookie scookies[]=new ServerCookie[INITIAL_SIZE];

/** Register a new, unitialized cookie. Cookies are recycled, and

*  most of the time an existing ServerCookie object is returned.

*  The caller can set the name/value and attributes for the cookie

*/

public ServerCookie addCookie() {

if( cookieCount >= scookies.length  ) {

ServerCookie scookiesTmp[]=new ServerCookie[2*cookieCount];

System.arraycopy( scookies, 0, scookiesTmp, 0, cookieCount);

scookies=scookiesTmp;

}

ServerCookie c = scookies[cookieCount];

if( c==null ) {

c= new ServerCookie();

scookies[cookieCount]=c;

}

cookieCount++;

return c;

}

/** Add all Cookie found in the headers of a request.

*/

public  void processCookies( MimeHeaders headers ) {...

/**

* Parses a cookie header after the initial "Cookie:"

* [WS][$]token[WS]=[WS](token|QV)[;|,]

* RFC 2965

* JVK

*/

public final void processCookieHeader(byte bytes[], int off, int len){...}

}

//为什么要多这个对象StandardSessionFacade?????

public class StandardSessionFacade implements HttpSession {

private HttpSession session = null;

}

/**

* Standard implementation of the <b>Session</b> interface.  This object is

* serializable, so that it can be stored in persistent storage or transferred

* to a different JVM for distributable session support.

* If you add fields to this class, you must

* make sure that you carry them over in the read/writeObject methods so

* that this class is properly serialized.

*/

public class StandardSession implements HttpSession, Session, Serializable {

/**

* The time this session was created, in milliseconds since midnight,

* January 1, 1970 GMT.

*/

protected long creationTime = 0L;

/**

* Return the <code>HttpSession</code> for which this object

* is the facade.

*/

protected static HttpSessionContext sessionContext = null;

protected transient StandardSessionFacade facade = null;

public HttpSession getSession() {

return (facade);

}

/**

* The HTTP session context associated with this session.

*/

/**

* Inform通知 the listeners about the new session.此类中有多种多个event、listener

*/

public void tellNew() {...}

/**

* Update the accessed time information for this session.  This method

* should be called by the context when a request comes in for a particular

* session, even if the application does not reference it.

* 会被invokeHttp11NioProcessor之类的invoke(request, response)调用;

*/

public void access() {...}

}

/**

* Standard implementation of the <b>Server</b> interface, available for use

* (but not required) when deploying and starting Catalina.

*

* @author Craig R. McClanahan

* @version $Id: StandardServer.java 1066492 2011-02-02 15:02:49Z kkolinko $

*/

public final class StandardServer implements Lifecycle, Server, MBeanRegistration {

awaitSocket = new ServerSocket(port, 1,InetAddress.getByName("localhost"));

}

好多类中都会创建ServerSocket比如下面这几个:

org\apache\coyote\http11\Http11Protocol.java

org\apache\jk\common\ChannelNioSocket.java

ServerSocketChannel ssc = ServerSocketChannel.open();

org\apache\jk\common\ChannelSocket.java

ServerSocket sSocket = new ServerSocket( i, backlog );

org\apache\tomcat\util\net\JIoEndpoint.java

serverSocket = serverSocketFactory.createSocket(port, backlog);

org\apache\tomcat\util\net\NioEndpoint.java

serverSock = ServerSocketChannel.open();

其实创建一个 session 并不耗什么资源,无非就是一个空的map,就是别往里面塞太多的东西,尤其是在集群环境下,会增加同步的负担。

在文件《D:\study\src_zip\org\apache\catalina\core\StandardServer.java》中查找:"getInputStream"

stream = socket.getInputStream();

(精)tomcat 源码学习相关推荐

  1. Tomcat源码学习(一)

    Tomcat源码学习(一) 已有 9159 次阅读 2008-3-13 03:10 |个人分类:Tomcat|系统分类:开发 http://blog.ccidnet.com/home.php?mod= ...

  2. tomcat源码学习

    2019独角兽企业重金招聘Python工程师标准>>> 1.下载源码 在eclicpse 用svn导入源码   http://svn.apache.org/repos/asf/tom ...

  3. 【Tomcat源码学习】-2.容器管理

    Tomcat作为应用服务器,我们可以理解Tomcat本身就是一个容器,用于装载应用,而作为容器本身是由若干组件以及事件构成,容器管理即为管理容器的有机组成部分. 一.Tomcat整体结构: Serve ...

  4. Tomcat源码学习(9)-How Tomcat works(转)

    第2章:一个简单的Servlet容器 概要 本章通过两个程序来说明你如何开发自己的servlet容器.第一个程序被设计得足够简单使得你能理解一个servlet容器是如何工作的.然后它演变为第二个稍微复 ...

  5. Tomcat源码学习(4)-How Tomcat works(转)

    ServerSocket类 Socket类代表一个客户端套接字,即任何时候你想连接到一个远程服务器应用的时候你构造的套接字,现在,假如你想实施一个服务器应用,例如一个HTTP服务器或者FTP服务器,你 ...

  6. Tomcat源码学习(7)-How Tomcat works(转)

    Response类 ex01.pyrmont.Response类代表一个HTTP响应,在Listing 1.6里边给出.          Listing 1.6: Response类 package ...

  7. 2021-03-19Tomcat源码学习--WebAppClassLoader类加载机制

    Tomcat源码学习--WebAppClassLoader类加载机制 在WebappClassLoaderBase中重写了ClassLoader的loadClass方法,在这个实现方法中我们可以一窥t ...

  8. tomcat依赖导入步骤_图说tomcat(三)导入tomcat源码到idea

    前面两篇文章中我们提到了寻找tomcat的main函数,还有tomcat的启动加载过程,第一个还好,基本上都是通过.sh文件来看的,但第二个如果直接通过文本打开java文件就有点痛苦了,可能小伙伴看的 ...

  9. 蘑菇君深入源码学习Tomcat系列 (1) - Tomcat与Servlet的那些事

    瞎扯淡 最近很焦虑,每天过着咸鱼般的生活,感觉前途渺茫.再这么下去,整个人就真成咸鱼了.焦虑来源于日复一日工作中,自己变得越来越麻木,不会动脑思考.憋说举一反三了,脑子多转一下都感觉要耗尽全身气力. ...

最新文章

  1. boost::mpl模块实现same_as相关的测试程序
  2. 状态模式 处理订单状态_将状态机模式实现为流处理器
  3. HDU1573-模线性方程
  4. 完美者右键扩展菜单管理器 1.2.1 中文绿色版
  5. 【Kafka】kafka检查消费者位置
  6. 《编写可维护的Javascript》学习总结
  7. Serializable接口序列化与反序列化
  8. 无缓冲I/O与有缓冲I/O区别
  9. html 页面循环判断值,变量交换,判断有值、数字,for循环.html
  10. Vijos 1041题:神风堂人数
  11. Silverlight下载-Silverlight 1.1 Tools下载
  12. web漏洞扫描器原理_漏洞扫描技巧篇——Web漏洞扫描器
  13. CI框架实现框架前后端分离的方法详解:把前端代码统一管理
  14. AIL(Android init Language)
  15. 2019个人目标——计划未来
  16. acml会议级别_人工智能领域的顶级学术会议大全(二)
  17. Android 对一个View进行缩放处理(放大或缩小View)案例
  18. IntelliJ IDEA如何修改版权信息
  19. Python爬取网上车市[http://www.cheshi.com/]的数据
  20. STL教程:C++ STL快速入门

热门文章

  1. Python脚本--Apache配置文件
  2. Linux 下Oracle11g 自动随系统启动
  3. android studio 运行 Java Application
  4. 内存可见性和原子性:Synchronized和Volatile的比较
  5. 8个适合用来练手的SpringBoot开源项目
  6. NDK学习笔记-JNI的引用
  7. Echart---多项柱状图-2D/H5
  8. dos命令行输入adb shell命令为什么报错
  9. winform 代码定义事件
  10. Mysql的sql语句,Delete 中包含 not in