tomcat7源码分析

tomcat7源码分析

本篇分为六个部分:

tomcat基本框架

tomcat启动流程简介

tomcat启动流程源码分析

tomcat处理一个请求过程分析

.jsp生成.java和.class流程分析

apache beachmark性能测试

一、tomcat基本框架

由三部分组成:

组件架构:组件搭起房梁

基于JMX:JMX管理组件等对象

事件侦听:通过事件变更状态

  1. 组件架构结构

1.1 结构图:



组件简述:
Catalina:与开始/关闭shell脚本交互的主类,因此如果要研究启动和关闭的过程,就从这个类开始看起。


Server:是整个Tomcat组件的容器,包含一个或多个Service。


Service:Service是包含Connector和Container的集合,Service用适当的Connector接收用户的请求,再发给相应的Container来处理。


Connector:实现某一协议的连接器,如默认的有实现HTTP、HTTPS、AJP协议的。


Container:可以理解为处理某类型请求的容器,处理的方式一般为把处理请求的处理器包装为Valve对象,并按一定顺序放入类型为Pipeline的管道里。Container有多种子类型:Engine、Host、Context和Wrapper,这几种子类型Container依次包含,处理不同粒度的请求。另外Container里包含一些基础服务,如Loader、Manager和Realm。


Engine:Engine包含Host和Context,接到请求后仍给相应的Host在相应的Context里处理。


Host:就是我们所理解的虚拟主机。


Context:就是我们所部属的具体Web应用的上下文,说白了就是我们的应用,每个请求都在是相应的上下文里处理的。


Wrapper:Wrapper是针对每个Servlet的Container,每个Servlet都有相应的Wrapper来管理。


可以看出Server、Service、Connector、Container、Engine、Host、Context和Wrapper这些核心组件的作用范围是逐层递减,并逐层包含。


下面就是些被Container所用的基础组件:


Loader:是被Container用来载入各种所需的Class。


Manager:是被Container用来管理Session池。


Realm:是用来处理安全里授权与认证。



1.2 组件关系

service直接包含connector(可多个)containtor(一个),这好比一个家庭,男主外,女主内。service是房子,connector是男子,主要工作是对外;Container是女子,处理家里内部事务。connector和service一起组件一个家庭,住在service这个房子里
  1. JMX管理组件
Tomcat会为每个组件进行注册过程,通过Registry管理起来,而Registry是基于JMX来实现的,因此在看组件的init和start过程实际上就是初始化MBean和触发MBean的start方法,会大量看到形如:


Registry.getRegistry(null, null).invoke(mbeans, "init", false);


Registry.getRegistry(null, null).invoke(mbeans, "start", false);


这样的代码,这实际上就是通过JMX管理各种组件的行为和生命期。
  1. 事件侦听
各个组件在其生命期中会有各种各样行为,而这些行为都有触发相应的事件,Tomcat就是通过侦听这些时间达到对这些行为进行扩展的目的。在看组件的init和start过程中会看到大量如:


lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);这样的代码,这就是对某一类型事件的触发,如果你想在其中加入自己的行为,就只用注册相应类型的事件即可。

二、tomcat启动流程简介

启动时主要流程如下:
1. 初始化类加载器:主要初始化Tomcat加载自身类库的StandardClassLoader(commonClassLoader等)。

  1. 解析conf/serverl.xml配置文件:使用Digester解析Tomcat的server.xml(SAXReader),初始化各个组件(包含各个web应用,解析对应的web.xml进行初始化)。

  2. 初始化容器:初始化Service的各级容器Container,包括我们Web应用(我们熟悉的Listener,Filter,Servlet等初始化等在这里完成)。

  3. 初始化Connector:初始化Service的的Connector

  4. 初始化后,等待请求的到来

  5. 时序图

从上图可以看出,Tomcat启动分为init和start两个过程,核心组件都实现了Lifecycle接口,都需实现start方法,因此在start过程中就是从Server开始逐层调用子组件的start过程。
下面我们就根据时序图结合源码进行分析

三、tomcat7启动流程源码分析

从catalina.bat找到启动开始的地方:Bootstrap类,它中有个main方法

set _EXECJAVA=%_RUNJAVA%
set MAINCLASS=org.apache.catalina.startup.Bootstrap
set ACTION=start
set SECURITY_POLICY_FILE=
set DEBUG_OPTS=
set JPDA=

Bootstrap.main开始

public static void main(String args[]) {
        System.out.println("-- my test starting --");


        if (daemon == null) { 
            // Don't set daemon until init() has completed
            Bootstrap bootstrap = new Bootstrap();
            try {
                //set一些系统属性、初始化classLoader和Catalina.setParentClassLoader()
                bootstrap.init()
            } catch (Throwable t) {}
            daemon = bootstrap;
        } 

        String command = "start";


        if (command.equals("start")) {
            daemon.setAwait(true);

            //加载配置资源,通过反射调用catalina.load方法,利用catalina.load方法创建digester实例,从而解析conf/server.xml文件
            daemon.load(args);

            //运行各个组件,容器开始启动
            daemon.start();
        }
}

从代码可以看出,main方法主要做三件事:

init、load、start

init: 初始化类加载器
load:加载conf/server.xml,根据规则解析元素为对应对象,并set属性,元素间关联关系,且变更各个对象生命周期状态
start:启动各个组件
调用Bootstrap.init()

主要做了两件事:
1. 设置catalinahome和catalinbase(即java的vm options的值:”E:\tomcat_test\apache-tomcat-7.0.73-src\lunch”
2. 实例化**ClassLoaders

public void init() throws Exception {
        // Set Catalina path
        setCatalinaHome();
        setCatalinaBase();


        //实例化**ClassLoaders,创建URLClassLoader
        initClassLoaders();


        Thread.currentThread().setContextClassLoader(catalinaLoader);


        SecurityClassLoad.securityClassLoad(catalinaLoader);


        // Load our startup class and call its process() method
        Class<?> startupClass = catalinaLoader.loadClass ("org.apache.catalina.startup.Catalina");
        Object startupInstance = startupClass.newInstance();


        catalinaDaemon = startupInstance;


    }
调用Bootstrap.load(args)

通过反射实例化org.apache.catalina.startup.Catalina,并调用catalina.load(),在load方法中做了下面的事:
1. Digester类按照预定的规则解析server.xml,元素转化为对象,包括构造对象,set属性到对象字段,同时维护相互关联关系
2. 调用Server.init()方法,这其中会一连串的发布事件病调用各个service.init()方法,完成各个组件的初始化,各个组件包括:StandardServer、StandardService、StandardEngine、StandardHost、StandardContext、StandardWrapper。从StandardServer.init()到StandardWrapper.init()演示了这一过程

Catalina.load()
public void load() {
    // Create and execute our Digester
    //预定义了解析规则
    Digester digester = createStartDigester();


    try {
        // 获取conf/server.xml文件
        file = configFile();
        inputStream = new FileInputStream(file);
        inputSource = new InputSource(file.toURI().toURL().toString());

        inputSource.setByteStream(inputStream);
        digester.push(this);
        // 解析conf/server.xml文件(SAX),并根据规则初始化各个组件实例和关联关系:如server元素实例化standardServer实例对象,把属性内容set到对应实例中
        digester.parse(inputSource);
    } catch (SAXParseException spe) {

    } 
    // server关联catalina,在解析server.xml过程中,会发现父子元素对应实例的相互关联性(双向性)
    getServer().setCatalina(this);


    // Start the new server
    try {
        // 调用各个组件的init方法,初始化各个组件  
        getServer().init();
    } catch (LifecycleException e) {

    }
}



StandardServer.init()

上述各个组件有个共同的父类:LifecycleBase,用于管理组件的生命周期和状态变化。在走Server.init()前,先走父类LifecycleBase.init()方法,事件驱动当前组件状态的变化

LifecycleBase.init()

变更状态(通过事件变更),进入子类initInternal()方法

public final synchronized void init() throws LifecycleException {
    try {
        //变更生命周期状态(通过事件变更)
        setStateInternal(LifecycleState.INITIALIZING, null, false);
        // 进入子类的initInternal()方法
        initInternal();
        setStateInternal(LifecycleState.INITIALIZED, null, false);
    } catch (Throwable t) {}
}

从StandardServer到StandardWrapper,都会调用initInternal(),并伴随调用共有父类LifecycleBase.init()

StandardServer.init()方法

核心代码功能:
1. 注册mbean
2. 调用service.init()方法,同样,先走LifecycleBase.init()

protected void initInternal() throws LifecycleException {
    // Register the MBeanFactory
    MBeanFactory factory = new MBeanFactory();
    factory.setContainer(this);
    onameMBeanFactory = register(factory, "type=MBeanFactory");

    // Register the naming resources
    globalNamingResources.init();

    // Initialize our defined Services
    for (int i = 0; i < services.length; i++) {
        services[i].init();
    }
}

service.initIn

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值