`

tomcat 源码学习

 
阅读更多

 

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();   

 

分享到:
评论
1 楼 Nabulio 2016-06-16  
厉害

相关推荐

    tomcat源码学习之环境搭建

    在深入探讨Tomcat源码学习之前,我们首先要理解Tomcat是什么。Tomcat是一款开源的、免费的Web服务器和Servlet容器,由Apache软件基金会维护。它实现了Java Servlet和JavaServer Pages(JSP)规范,是Java EE应用...

    Tomcat源码学习:一个最简单的“Tomcat”

    【标题】"Tomcat源码学习:一个最简单的‘Tomcat’",这篇博客主要探讨的是如何通过学习Tomcat的源代码来理解这个流行的开源Java Servlet容器的工作原理。Tomcat是Apache软件基金会的一个项目,它是Java Web应用...

    tomcat源码学习

    【标题】"Tomcat源码学习"涉及到的是对Apache Tomcat服务器内部运行机制的深入理解。Tomcat是一款广泛使用的开源Java Servlet容器,它实现了Java EE的Web应用规范,特别是Servlet和JSP。源码学习是提升技术水平、...

    tomcat 源码 学习

    通过阅读相关网络博客,如《(转)Tomcat源码学习(一) - flm_llx的日志 - 网易博客》和《Tomcat源码学习(二) - Carl -- IT博客-中国最具人气的IT博客-赛迪网IT人家园》,你可以获取更多具体细节和实战经验。...

    Tomcat源码学习(一) 源码编译和导入Eclipse

    【Tomcat源码学习(一) 源码编译和导入Eclipse】 在深入学习Tomcat源码之前,首先需要获取源码并将其配置到开发环境中,这通常涉及到源码下载、编译以及在集成开发环境(IDE)中导入项目。本篇文章将指导初学者完成...

    tomcat源码学习并添加注释学习

    【标题】:“Tomcat源码学习并添加注释学习” 【描述】:“Tomcat作为一款广泛应用的开源Web服务器和Servlet容器,是Java EE应用开发者的必备工具。通过深入学习Tomcat的源码,我们可以理解其内部工作原理,提高对...

    tomcat8 源码学习,欢迎大家下载,官网下载会出现下载不了的情况

    【标题】:Tomcat8源码学习 在Java Web开发领域,Tomcat是一个非常重要的应用服务器,它作为开源的...对于想要从事中间件开发或者希望提高Java Web性能优化能力的程序员来说,Tomcat源码学习是一条必不可少的道路。

    Tomcat源码 学习java很好的东东 apache-tomcat-6.0.26-src

    10. **性能优化**:Tomcat源码提供了很多可调整的参数,通过对这些参数的调整,可以优化内存使用、减少响应时间等,提升整体性能。 通过深入学习和理解"apache-tomcat-6.0.26-src"源码,开发者不仅可以提高Java Web...

    tomcat源码+文档pdf+源码解析

    源码解析部分则是对Tomcat源码的深度剖析,涵盖了关键类和方法的作用、设计模式的运用以及性能优化技巧。这有助于开发者理解Tomcat内部的工作流程,例如,如何处理HTTP请求的生命周期,以及线程池是如何调度和管理的...

    tomcat-demo:tomcat源码学习

    【标题】:“Tomcat-Demo:Tomcat源码学习” 【描述】:“对不起,原本这里应该是Tomcat官方的readme,但现在我将用它来记录我的Tomcat源码学习过程。” 【标签】:“系统开源” 在Java Web开发领域,Apache ...

    tomcat源码

    通过阅读和分析Tomcat源码,我们可以学习到以下知识点: 1. **Servlet生命周期**:Tomcat如何加载、初始化、服务、销毁Servlet,以及ServletConfig和ServletContext的角色。 2. **线程池管理**:Tomcat如何使用...

    tomcat 源码分析系列文档

    【标签】"tomcat源码分析"表明整个资料集专注于Tomcat的源代码级探索,适合于开发者或运维人员深入了解服务器的底层实现。 【文件名称列表】中的每个文档都对应一个特定主题: 1. "Tomcat处理HTTP请求源码分析.doc...

    tomcat源码导入myeclipse

    【标题】"Tomcat源码导入MyEclipse"是一个针对Java开发者的重要实践操作,它涉及到两个关键组件:Tomcat服务器和MyEclipse集成开发环境。Tomcat是Apache软件基金会的一个开源项目,它作为Servlet和JavaServer Pages...

    eclipse运行tomcat源码:修改源码:重新编译:重新打包

    文件描述: 1.tomcat源码文件 2.tomcat程序文件 3.Ant程序文件 4.tomcat源码在eclipse运行,重新编译,重新打包步骤文件 ...1.用于学习tomcat源码和了解tomcat运行机制 2.学习如何修改tomcat源码后如何重新编译,打包。

    tomcat5 源码学习,深度剖析tomcat一书的指定tomcat版本

    tomcat5 源码学习,深度剖析tomcat一书的指定tomcat版本,随着tomcat版本的升级,内容发生 了变化,但为了读懂书籍,还是得使用老版本得源码,欢迎大家下载,官网下载会出现下载不了的情况,我主页有tomcat4-tomcat9...

    tomcat8源码

    Apache Tomcat 8.5.23 源码分析 Apache Tomcat 是一个开源的、免费的Web服务器和Servlet容器,它实现了Java Servlet和JavaServer Pages(JSP)规范,...因此,对Tomcat源码的学习对于Java Web开发者来说是至关重要的。

    tomcat7源码

    源码分析是提升开发者对服务器内部运作机制理解的重要途径,尤其对于Tomcat这样的核心组件,源码的学习能够帮助我们更深入地理解Web应用的部署、运行以及性能优化。 首先,我们要了解Tomcat的架构。Tomcat7基于...

    tomcat9 源码学习

    源码学习对于理解Tomcat的工作原理、优化性能以及自定义功能至关重要。以下是一些在学习Tomcat9源码时会涉及的关键知识点: 1. **架构概述**:Tomcat由多个组件构成,如Catalina(核心Servlet容器)、 Coyote...

Global site tag (gtag.js) - Google Analytics