tomcat源码学习2------启动过程

这一次将会对tomcat的启动过程进行一个分析。

一、main函数分析

tomcat的入口函数是:org.apache.catalina.startup.main
在这个函数中最关键的代码段是:

    public static void main(String args[]) {
        //......
            String command = "start";
            if (args.length > 0) {
                command = args[args.length - 1];
            }

            if (command.equals("startd")) {
                args[args.length - 1] = "start";
                daemon.load(args);
                daemon.start();
            } else if (command.equals("stopd")) {
                args[args.length - 1] = "stop";
                daemon.stop();
            } else if (command.equals("start")) {
                daemon.setAwait(true);
                daemon.load(args);
                daemon.start();
            } else if (command.equals("stop")) {
                daemon.stopServer(args);
            } else if (command.equals("configtest")) {
                daemon.load(args);
                if (null==daemon.getServer()) {
                    System.exit(1);
                }
                System.exit(0);
            } else {
                log.warn("Bootstrap: command \"" + command + "\" does not exist.");
            }
        //......

    }

从这里我们可以看到,当启动参数为“start”的时候,实际调用的是Bootstrap.start()函数(daemon是一个Bootstrap类的实例),接下来分析start()函数。

二、start函数分析

Bootstrap.start()函数的代码:

    public void start()
        throws Exception {
        if( catalinaDaemon==null ) init();

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

    }

可以看出本质上调用的是catalinaDaemon的start函数,那么catalinaDaemon又是哪个类的实例呢?通过下面这段代码可以发现:

    public void init()throws Exception
    {

        // ......
        Class<?> startupClass =
            catalinaLoader.loadClass
            ("org.apache.catalina.startup.Catalina");
        Object startupInstance = startupClass.newInstance();
        //......
        catalinaDaemon = startupInstance;

    }

所以代码接下来将会走到org.apache.catalina.startup.Catalina.start()中去,

public void start() {

        if (getServer() == null) {
            load();
        }
        //......
        getServer().start();
        //......
        if (await) {
            await();
            stop();
        }
    }

在这里最关键的两个函数是:
1、load(),配置文件的加载
2、getServe日().start(),服务的启动。
还有一个地方需要注意的地方是await()函数,这个函数实际上是一直在监听shutdown命令,默认是8005端口,配置文件中可以设置。

三、配置文件加载

tomcat的配置文件加载是在org.apache.catalina.startup.Catalina.load()函数里面完成的,代码为:

    public void load() {
        //......
        Digester digester = createStartDigester();
        //......
        inputSource.setByteStream(inputStream);
        digester.push(this);
        digester.parse(inputSource);
        //......
        getServer().init();
        //......
    }

这个函数中主要干了三件事情:
1、构建了一个xml解析执行配置
2、解析配置文件,并根据第一步生成的构建方式来构建tomcat的所有实例。
3、初始化服务,这个服务实例是在第二步中构建的。初始化的逻辑过程和启动过程的逻辑非常相似,具体逻辑可以参考启动过程。
具体的加载过程将会在下一篇博客中进行分析。

四、服务的启动过程

在start函数中会调用getServer().start()函数,就是启动tomcat服务。通过分析可以知道getServer函数返回的是org.apache.catalina.core.StandardServer类的实例。start函数是在其基类org.apache.catalina.util.LifecycleBase中实现的,其关键代码为:

@Override
public final synchronized void start() throws LifecycleException {
    //......    
    startInternal();
    //......    
}

这个函数的本质是调用了startInternal函数,在StandardServer类中有实现这个函数,其关键代码为:

    @Override
    protected void startInternal() throws LifecycleException {

        // ......
        synchronized (services) {
            for (int i = 0; i < services.length; i++) {
                services[i].start();
            }
        }
    }

可以看出,在server的启动过程中实际上调用的是每一个services的start函数,这里的services默认都是StandardService的实例,而StandardService也是继承LifecycleBase的,所以本质上会再调用StandardService的startInternal函数,这个函数的关键代码:

    @Override
    protected void startInternal() throws LifecycleException {


        //......
        if (container != null) {
            synchronized (container) {
                container.start();
            }
        }
        //......
        synchronized (executors) {
            for (Executor executor: executors) {
                executor.start();
            }
        }
        //......
        synchronized (connectors) {
            for (Connector connector: connectors) {
                try {
                    // If it has already failed, don't try and start it
                    if (connector.getState() != LifecycleState.FAILED) {
                        connector.start();
                    }
                } catch (Exception e) {
                    log.error(sm.getString(
                            "standardService.connector.startFailed",
                            connector), e);
                }
            }
        }
    }

这个函数中主要做了三件事情:
1、调用container的start函数,container默认是org.apache.catalina.core.StandardEngine的实例,它也是继承LifecycleBase的。
2、调用所有的Executor的start函数,Executor 也是继承LifecycleBase的。
3、调用所有的connector的start函数,connector是org.apache.catalina.connector.Connector的实例,它也是继承LifecycleBase的。

container的start代码本质上是执行的ContainerBase.startInternal函数,其关键代码为:

@Override
    protected synchronized void startInternal() throws LifecycleException {

        // ......
        if ((loader != null) && (loader instanceof Lifecycle))
            ((Lifecycle) loader).start();
        logger = null;
        getLogger();
        if ((manager != null) && (manager instanceof Lifecycle))
            ((Lifecycle) manager).start();
        if ((cluster != null) && (cluster instanceof Lifecycle))
            ((Lifecycle) cluster).start();
        Realm realm = getRealmInternal();
        if ((realm != null) && (realm instanceof Lifecycle))
            ((Lifecycle) realm).start();
        if ((resources != null) && (resources instanceof Lifecycle))
            ((Lifecycle) resources).start();

        // Start our child containers, if any
        Container children[] = findChildren();
        List<Future<Void>> results = new ArrayList<Future<Void>>();
        for (int i = 0; i < children.length; i++) {
            results.add(startStopExecutor.submit(new StartChild(children[i])));
        }

        boolean fail = false;
        for (Future<Void> result : results) {
            try {
                result.get();
            } catch (Exception e) {
                log.error(sm.getString("containerBase.threadedStartFailed"), e);
                fail = true;
            }

        }
        //......
        if (pipeline instanceof Lifecycle)
            ((Lifecycle) pipeline).start();


        setState(LifecycleState.STARTING);

        // Start our thread
        threadStart();

    }

在这里同样是调用了一大堆LifecycleBase实例的start函数进行启动。

connector的start调用的关键代码:

    @Override
    protected void startInternal() throws LifecycleException {
        //......
        protocolHandler.start();
        //......
    }

这里最关键的是调用了http的handler的start,启动了以太网服务器,等待接收数据,具体的启动和执行原理将在以后分析。

至此tomcat的启动过程已经初步分析玩了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值