tomcat容器启动

tomcat文件结构

155803_cjMr_2457218.png

其中conf中有一些比较重要的文件,如下:

catalina.propertiesTomcat环境变量配置
catalina.policy安全模式下运行时的默认安全策略
context.xml所有web应用需要加载的Context配置,如果用户指定了自己的Context,这个文件将会被覆盖
logging.propertiesTomcat日志文件,可以修改tomcat的日志级别
Server.xmlTomcat的很很重要的配置文件,配置连接器,监听端口,服务器实例等,tomcat优化相关也均会配置在此文件中
tomcat-users.xmlTomcat manager认证
web.xmlTomcat默认的web.xml文件,定义了基础的Servlet和MIME映射。如果应用中没有web.xml,则tomcat会使用此文件作为默认文件

启动脚本

当我们下载下来tomcat以后,在bin文件夹下,tomcat分别提供了linux和windows的启动脚本文件,startup.bat和startup.sh,这个文件没有实质性的用处,主要是为了引导执行catalina.sh(或者catalina.bat)文件,所以我们在启动tomcat时,也可以直接启动catalina.sh。这个文件内容特别多,有500多行,是tomcat启动的核心文件。主要分为以下几方面内容

1.   设置CATALINA_HOME和CATALINA_BASE

2.   寻找是否有setevn.sh和setclasspath.sh文件,并加载,我们自定义的tomcat参数,例如设置jvm参数的大小,就可以在新建一个setevn.sh文件,然后在这个文件中配置,tomcat会自动加载这个文件。setclasspath.sh是一些必要的批处理脚本,它只负责查找和检查JAVA_HOME和JRE_HOME两个环境变量。

3.   设置日志组件。

4.   根据不同的配置组装最后要启动的命令参数。

5.   执行启动命令

 启动类

 tomcat的启动类是Bootstrap.java,类首先通过静态方法加载catalina.base和catalina.home的位置,然后实例化Bootstarp类,通过调用init方法进行初始化。初始化时,加载

${catalina.base}/lib,${catalina.base}/lib/*.jar,"${catalina.home}/lib,${catalina.home}/lib/*.jar 这些文件夹以及jar文件。并创建tomcat原始的ClassLoader。然后通过classLoader实例化org.apache.catalina.startup.Catalina类并进行初始化其parentClassLoader,然后此函数线程作为守护线程。

默认的启动参数是start,当参数是start时代表是启动tomcat,实际上是调用Catalina.java的load()和start()函数进行启动。接下来分别看一下这两个函数

load()函数

load函数会实例化出来一个Server实例。每个tomcat只能有一个server实例。server节点是server.xml的根节点,tomcat所有的配置也都是在这这个节点之下,下属节点主要分为连接器,监听器,容器这几类。

public void load() {

        long t1 = System.nanoTime();
		//设置临时文件目录
        initDirs();
		
        // 初始化digester框架可能用的一些naming信息
        initNaming(); 

        // 创建Digester对象,并且做节点和相关实体类的映射对照关系
        Digester digester = createStartDigester();

        InputSource inputSource = null;
        InputStream inputStream = null;
        File file = null;
        try {
			
            	//巴拉巴拉一大堆,就是为了加载server.xml文件到digester中
            }

            try {
                inputSource.setByteStream(inputStream);
                digester.push(this);
                digester.parse(inputSource);
            } catch (SAXParseException spe) {
               
            }
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    // Ignore
                }
            }
        }
		
	 
	/**
初始化Server的一些最基本的信息
 server指的是org.apache.catalina.Server,这个也就是tomcat的顶级容器
	**/
        getServer().setCatalina(this);
        getServer().setCatalinaHome(Bootstrap.getCatalinaHomeFile());
        getServer().setCatalinaBase(Bootstrap.getCatalinaBaseFile());

        // Stream redirection
        initStreams();
        try {
        	/**
        	 * 初始化Server信息,Server是一个接口,默认实现是StandardServer
        	 * StandardServer继承自抽象类LifecycleBase,init方法由其实现,tomcat的容器的默认实现均继承自此抽象类,并且实现lifecycle接口,LifecycleBase中有抽象方法startInternal()由其子类进行实现
        	 * 具体的针对tomcat容器的启动方式稍后再做分析
        	 */
            getServer().init();
        } catch (LifecycleException e) {
            if (Boolean.getBoolean("org.apache.catalina.startup.EXIT_ON_INIT_FAILURE")) {
                throw new java.lang.Error(e);
            } else {
                log.error("Catalina.start", e);
            }
        }

start函数

public void start() {
    	
    	//重复的加载server,以保证server不是空的,重复加载以后如果server依然为空,则抛出异常,启动失败
        if (getServer() == null) {
            load();
        }
        if (getServer() == null) {
            log.fatal("Cannot start server. Server instance is not configured.");
            return;
        }

        long t1 = System.nanoTime();

        // Start the new server
        try {
        	//启动server容器
            getServer().start();
        } catch (LifecycleException e) {
            log.fatal(sm.getString("catalina.serverStartFail"), e);
            try {
                getServer().destroy();
            } catch (LifecycleException e1) {
                log.debug("destroy() failed for failed Server ", e1);
            }
            return;
        }

        long t2 = System.nanoTime();
        if(log.isInfoEnabled()) {
            log.info("Server startup in " + ((t2 - t1) / 1000000) + " ms");
        }

        // Register shutdown hook
        if (useShutdownHook) {
            if (shutdownHook == null) {
                shutdownHook = new CatalinaShutdownHook();
            }
            //增加关闭钩子,tomcat在关闭(不管是正常还是异常)时执行后续的收尾工作
            Runtime.getRuntime().addShutdownHook(shutdownHook);

            // If JULI is being used, disable JULI's shutdown hook since
            // shutdown hooks run in parallel and log messages may be lost
            // if JULI's hook completes before the CatalinaShutdownHook()
            LogManager logManager = LogManager.getLogManager();
            if (logManager instanceof ClassLoaderLogManager) {
                ((ClassLoaderLogManager) logManager).setUseShutdownHook(
                        false);
            }
        }
        if (await) {
        	//开启ServerSocket,等待请求,并接收请求
            await();
            //去除关闭钩子,逐级关闭容器
            stop();
        }
    }

tomcat的容器以及启动

tomcat有四种容器,这个通过server.xml可以看出来

161109_rIsD_2457218.png

容器均实现Lifecycle接口,它的启动,是在通过调用StandardServer load方法时进行初始化,通过调用start方法进行启动。在Lifecycle的开头注释部分,非常明确的画出了整个容器的声明周期过程。

161127_8x7j_2457218.png

首先容器需要先调用init()方法进行初始化,初始化完成之后调用start()方法启动容器,当容器不再使用,调用stop()进行停止, 最后destory()方法销毁容器

在启动的过程中,由于涉及到很多的事件,对于各种事件的处理不可能硬编码到代码中,并且了为了可扩展,lifecycle定义了很多的事件监听点,用到自定义实现的观察者设计模式。各个事件的监听器可以注册自己感兴趣的事件,当这事件发生时会进行通知。

生命周期时期

调用事件

init

在init之前会调用前后会分别调用注册了以下事件的方法

BEFORE_INIT_EVENT

AFTER_INIT_EVENT

start

在接收到start命令时,调用START_EVENT

Start之前调用BEFORE_START_EVENT,容器启动之后调用注册了AFTER_START_EVENT事件的方法。

stop

接收到stop命令,会调用STOP_EVENT的事件,

Stop之前调用BEFORE_STOP_EVENT,之后调用AFTER_STOP_EVENT

destroy

容器销毁之前调用AFTER_DESTROY_EVENT,销毁之后调用感兴趣的注册了BEFORE_DESTROY_EVENT事件的类的方法

除了以上还提供了PERIODIC_EVENT事件,这个注册此时间的方法会被周期性的执行,配合CONFIGURE_START_EVENT和CONFIGURE_STOP_EVENT事件的使用,可以监控配置文件是否修改,然后进行热部署的效果。

 

tomcat容器的启动采用的是链式启动结构,有父容器进行查找其下面的字容器进行启动。例如我们启动Engine,它会自动的找它下面的Host,启动Engine的同时进行启动host。

161221_eA8f_2457218.png

容器均实现Container接口, ContainerBase,以Standardxxx开头的类是容器的默认实现,Container接口中有一个findChinldren()方法,用来查找这个容器下的子容器,默认由ContainerBase实现,container接口有一个默认的抽象实现类ContainerBase实现,而findChinldren()方法也默认由其实现。容器的默认实现Standardxxx 继承自ContainerBase。

 

而整个tomcat的启动的概要流程图可以表示如下:

转载于:https://my.oschina.net/u/2457218/blog/1535945

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值