tomcat容器启动

tomcat文件结构

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

catalina.properties Tomcat环境变量配置
catalina.policy 安全模式下运行时的默认安全策略
context.xml 全部web应用须要加载的Context配置,若是用户指定了本身的Context,这个文件将会被覆盖
logging.properties Tomcat日志文件,能够修改tomcat的日志级别
Server.xml Tomcat的很很重要的配置文件,配置链接器,监听端口,服务器实例等,tomcat优化相关也均会配置在此文件中
tomcat-users.xml Tomcat manager认证
web.xml Tomcat默认的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启动的核心文件。主要分为如下几方面内容linux

1.   设置CATALINA_HOME和CATALINA_BASEweb

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

3.   设置日志组件。windows

4.   根据不一样的配置组装最后要启动的命令参数。设计模式

5.   执行启动命令tomcat

 启动类

 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能够看出来

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

首先容器须要先调用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。

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

 

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

相关文章
相关标签/搜索