Tomcat源码学习--Bootstrap启动

287 阅读7分钟

1.Bootstrap.main()

main方法中主要由三件事:

  1. BootStrap对象初始化:bootstrap.init()方法初始化bootastrap对象的三个类加载器、通过反射构造Catalina对象并赋值给bootstrap对象的catalinaDaemon属性、通过反射给Catalina对象设置parentClassLoader(注意bootstrap对象的sharedLoader和Catalina对象的parentClassLoader使用的是同一个ClassLoader)
  2. daemon.load(args):设置一些启动参数 3.daemon.start():调用Catalina对象的start方法
public static void main(String args[]) {
    synchronized (daemonLock) {
        if (daemon == null) {
            Bootstrap bootstrap = new Bootstrap();
            try {
                bootstrap.init();
            } catch (Throwable t) {
               ...
            }
            daemon = bootstrap;
        } else {
            ...
        }
    }
    try {
        String command = "start";
        if (args.length > 0) {
            ...
        } else if (command.equals("start")) {
            daemon.setAwait(true);
            daemon.load(args);
            daemon.start();
            if (null == daemon.getServer()) {
                System.exit(1);
            }
        ...
        } else {
            log.warn("Bootstrap: command "" + command + "" does not exist.");
        }
    } catch (Throwable t) {
        ...
    }
}
public void start() throws Exception {
    if (catalinaDaemon == null) {
        init();
    }
    // 在前面的初始化方法中我们知道catalinaDaemon设置的属性是Catalina类型的对象(通过反射生成的对象)
    Method method = catalinaDaemon.getClass().getMethod("start", (Class [])null);
    method.invoke(catalinaDaemon, (Object [])null);
}

2.Catalina.start()

在Catalina中start方法又是一系列的准备,然后调用了一个getServer().start()方法。getServer()方法返回的就是当前对象的server属性(实际上Tomcat的最顶级容器就是Server)

public void start() {
    if (getServer() == null) {
        //如果getServer为空,则调用load方法,设置当前对象的的server属性的值
        //实际上在Bootstrap的laod方法中就通过反射调用课Catalina的load方法,所以正常情况下这个getServer()不会返回空值
        load();
    }
    if (getServer() == null) {...}
    long t1 = System.nanoTime();
    try {
        //关键代码是这一行
        getServer().start();
    } catch (LifecycleException e) {
        try {
            getServer().destroy();
        } catch (LifecycleException e1) {...}
        return;
    }
    ...
}

稍微看一下load方法:

public void load() {
    if (loaded) {return;}
    loaded = true;
    long t1 = System.nanoTime();
    initDirs();
    // 在执行一些Digester之前的一些准备动作
    initNaming();
    // 创建和配置我们将用于启动的 Digester(一个XML解析器)
    Digester digester = createStartDigester();
    InputSource inputSource = null;
    InputStream inputStream = null;
    File file = null;
    try {
        //接下来一系列动作就是获取inputSource inputStream,实际上就是读取启动配置文件conf/server.xml
        ...
        try {
            inputSource.setByteStream(inputStream);
            // 将当前对象this推入到栈顶(即解析结果中此Catalina对象为根节点)
            digester.push(this);
            //解析指定输入源的内容,这里是根据conf/server.xml配置文件中的动态参数解析
            digester.parse(inputSource);
        } catch (SAXParseException spe) {...}
    } finally {...}
    // 将当前Catalina对象(this)设置给Server(实际上Server是一个接口,实现类是org.apache.catalina.core.StandardServer)
    getServer().setCatalina(this);
    // 设置Catalina的home和base(这两个File的默认路径就是Tomact文件夹的绝对路径)
    getServer().setCatalinaHome(Bootstrap.getCatalinaHomeFile());
    getServer().setCatalinaBase(Bootstrap.getCatalinaBaseFile());
    initStreams();
    // Start the new server
    try {
        // 启动Server,这里getServer()返回值实际上是:org.apache.catalina.core.StandardServer
        // 参见org.apache.catalina.startup.Catalina的createStartDigester方法
        getServer().init();
    } catch (LifecycleException e) {...}
    ...
}

简单看一下createStartDigester方法

protected Digester createStartDigester() {
    ...
    // 设置Server
    // addObjectCreate 为指定参数添加“对象创建”规则。就是创建一个指定类型的server对象
    digester.addObjectCreate("Server", // 对应server.xml 的 <Server>节点
                             "org.apache.catalina.core.StandardServer",// 属性实际类型为:org.apache.catalina.core.StandardServer
                             "className");
    // 为指定参数添加“设置属性”规则。
    digester.addSetProperties("Server");
    // 为指定参数添加“设置下一个”规则。
    digester.addSetNext("Server",
                        "setServer", // 调用setServer方法,设置属性,实际执行解析时是调用的catalina.serServer(),为什么是catalina ?因为在代码中parse之前先执行了digester.push(this)即将catalina对象作为根节点
                        //属性抽象类型为org.apache.catalina.Server接口,StandardServer实现了Server接口
                        "org.apache.catalina.Server");

    digester.addObjectCreate("Server/Service", // 对应server.xml 的 <Server> -> <Service>节点
                             "org.apache.catalina.core.StandardService",// 属性实际类型为:org.apache.catalina.core.StandardService
                             "className");
    digester.addSetProperties("Server/Service");
    digester.addSetNext("Server/Service",
                        "addService", // 这里调用的是StandardServer的addService方法,因为上一节点是Server
                        // 属性抽象类型为org.apache.catalina.Service,StandardService实现了Service接口
                        "org.apache.catalina.Service");
    ...  
    return digester;
}

通过上述分析:发现Catalina.start()调用了getServer().start(), getServer返回的实际是StandardServer类型的对象(在load方法中实例化Catalina时设置的Server属性),代码跟进: getServer().start() -> Lifecycle.start() ->LifecycleBase.start() -> startInternal() -> StandardServer.startInternal()

StandardServer.png 以上是StandardServer的UML图

3.LifecycleBase.start()

LifecycleBase是一个抽象类,start方法是一个模板方法

public final synchronized void start() throws LifecycleException {
    ...
    if (state.equals(LifecycleState.NEW)) {
        init();
    } else if (state.equals(LifecycleState.FAILED)) {
        stop();
    } else if (!state.equals(LifecycleState.INITIALIZED) &&
            !state.equals(LifecycleState.STOPPED)) {
        invalidTransition(Lifecycle.BEFORE_START_EVENT);
    }
    try {
        setStateInternal(LifecycleState.STARTING_PREP, null, false);
        // 这里调用自身的 startInternal方法
        startInternal();
        ...
    } catch (Throwable t) {
        ...
    }
}

4.StandardServer.startInternal()

在一个Tomcat中可以有多个Service,在StandardServer中启动时会遍历所有的Service一个一个启动。

protected void startInternal() throws LifecycleException {
    fireLifecycleEvent(CONFIGURE_START_EVENT, null);
    setState(LifecycleState.STARTING);
    globalNamingResources.start();
    // Start our defined Services
    synchronized (servicesLock) {
        for (Service service : services) {
            service.start();
        }
    }
}

一个Server下面多个Service.png

5.StandardService.startInternal()

StandardService的启动中主要有四个方法:

  1. engine.start();
  2. executor.start();
  3. mapperListener.start(); 这一步不怎么清楚,有熟悉的帮忙指点一下?
  4. connector.start();
protected void startInternal() throws LifecycleException {
    ...
    // 首先启动自定义的容器:engine的定义在server.xml中
    if (engine != null) {
        synchronized (engine) {
            // 启动Engine容器
            engine.start();
        }
    }
    synchronized (executors) {
        for (Executor executor: executors) {
            executor.start();
        }
    }
    // ????
    mapperListener.start();
    // 第二启动自定义的连接器:connector的定义在server.xml中有单独定义
    synchronized (connectorsLock) {
        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) {
                ...
            }
        }
    }
}

6.StandardEngine.startInternal()

Engine容器用于处理由连接器(connector)处理好的Request和Response。 Engine容器继承ContainerBase类,并实现了Container。

protected synchronized void startInternal() throws LifecycleException {
    // 标准容器启动,调用的是ContainerBase.startInternal()
    super.startInternal();
}

ContainerBase.startInternal()

protected synchronized void startInternal() throws LifecycleException {
    ...
    // Cluster启动
    Cluster cluster = getClusterInternal();
    if (cluster instanceof Lifecycle) {
        ((Lifecycle) cluster).start();
    }
    // Realm启动
    Realm realm = getRealmInternal();
    if (realm instanceof Lifecycle) {
        ((Lifecycle) realm).start();
    }

    // 启动子容器,StandardEngine调用的,所以这里的子容器都是Engine下面的容器,主要就是Host容器
    Container children[] = findChildren();
    List<Future<Void>> results = new ArrayList<>();
    for (Container child : children) {
        // 子容器启动另起线程,注意StartChild这个类
        results.add(startStopExecutor.submit(new StartChild(child)));
    }
    MultiThrowable multiThrowable = null;
    for (Future<Void> result : results) {
        try {
            // 校验线程运行结果,保证所有的子线程都执行成功
            result.get();
        } catch (Throwable e) {
            ...
        }
    }
    ...
    // 启动Engine中的pipeline
    if (pipeline instanceof Lifecycle) {
        ((Lifecycle) pipeline).start();
    }
    setState(LifecycleState.STARTING);
    // 启动将定期检查会话超时的后台线程
    threadStart();
}

StartChildContainerBase的一个内部类,只有一个私有Container类型的素有属性;并且实现了Callable接口,实现了call()方法,call()方法只有一行代码,即child.start()调用子容器的start方法。

private static class StartChild implements Callable<Void> {
    // Container类型的私有属性
    private Container child;
    // 设置属性值
    public StartChild(Container child) {
        this.child = child;
    }
    @Override
    public Void call() throws LifecycleException {
        // 调用子容器的strat方法
        child.start();
        return null;
    }
}

继续往下走,我们发现 Engine的容器时Host,实现类是StandardHost StandardHost.png

StandardHost的startInternal()方法中有这样一行代码:super.startInternal() 即又去调用ContainerBase.startInternal(), 继续找子容器,调用使用线程池调用子容器的启动方法。
调用链: StandardEngine.startInternal() -> ContainerBase.startInternal() -> StandardHost.startInternal() -> ContainerBase.startInternal() -> StandardContext.startInternal() -> ContainerBase.startInternal() -> StandardWrapper.startInternal() -> ContainerBase.startInternal() 直至到Wrapper再没有子容器,则Engine启动完毕。

7.StandardThreadExecutor.startInternal()

protected void startInternal() throws LifecycleException {
    taskqueue = new TaskQueue(maxQueueSize);
    TaskThreadFactory tf = new TaskThreadFactory(namePrefix,daemon,getThreadPriority());
    executor = new ThreadPoolExecutor(getMinSpareThreads(), getMaxThreads(), maxIdleTime, TimeUnit.MILLISECONDS,taskqueue, tf);
    executor.setThreadRenewalDelay(threadRenewalDelay);
    if (prestartminSpareThreads) {
        executor.prestartAllCoreThreads();
    }
    taskqueue.setParent(executor);
    setState(LifecycleState.STARTING);
}

8.MapperListener.startInternal()

  • addListeners(engine)
  • registerHost(host)
public void startInternal() throws LifecycleException {
    setState(LifecycleState.STARTING);
    // 得到 engine 容器
    Engine engine = service.getContainer();
    if (engine == null) {
        return;
    }
    // 找到默认主机
    findDefaultHost();
    // 给engine下的子容器一级一级添加MapperListener对象
    addListeners(engine);
    Container[] conHosts = engine.findChildren();
    for (Container conHost : conHosts) {
        Host host = (Host) conHost;
        if (!LifecycleState.NEW.equals(host.getState())) {
            // 注册主机将注册上下文和包装器
            registerHost(host);
        }
    }
}

递归执行,对每一个子容器添加MapperListener对象,MapperListener主要由两个变量: // 关联的映射器 host private final Mapper mapper; // 关联的Service (当前StandardService) private final Service service;

private void addListeners(Container container) {
    container.addContainerListener(this);
    container.addLifecycleListener(this);
    for (Container child : container.findChildren()) {
        addListeners(child);
    }
}

9.Connector.startInternal()

Connector处理请求是主要的组件是protocolHandler,在Connector初始化的过程时通过解析conf/server.xml中的Connector标签,并设置protocolHandler属性。 Connector标签.png 先看一下Connector的构造方法:

public Connector(String protocol) {
    // 调用了一个私有方法
    setProtocol(protocol);
    // 初始化 ProtocolHandler
    ProtocolHandler p = null;
    try {
        // 使用全类名 (protocolHandlerClassName )反射生成对象
        Class<?> clazz = Class.forName(protocolHandlerClassName);
        p = (ProtocolHandler) clazz.getConstructor().newInstance();
    } catch (Exception e) {
        ...
    } finally {
        this.protocolHandler = p;
    }
    ..
}

再看一下setProtocol(protocol)方法:

public void setProtocol(String protocol) {
    boolean aprConnector = AprLifecycleListener.isAprAvailable() &&
            AprLifecycleListener.getUseAprConnector();
    // 当配置文件中 protocol 为 "HTTP/1.1"时,如果不做修改,最终 protocolHandlerClassName的值为 "org.apache.coyote.http11.Http11NioProtocol"
    if ("HTTP/1.1".equals(protocol) || protocol == null) {
        if (aprConnector) {
            setProtocolHandlerClassName("org.apache.coyote.http11.Http11AprProtocol");
        } else {
            setProtocolHandlerClassName("org.apache.coyote.http11.Http11NioProtocol");
        }
    } else if ("AJP/1.3".equals(protocol)) {
        if (aprConnector) {
            setProtocolHandlerClassName("org.apache.coyote.ajp.AjpAprProtocol");
        } else {
            setProtocolHandlerClassName("org.apache.coyote.ajp.AjpNioProtocol");
        }
    } else {
        setProtocolHandlerClassName(protocol);
    }
}

从上面Connector的构造过程知道protocolHandler的实现类是:Http11NioProtocol

protected void startInternal() throws LifecycleException {
    ...
    try {
        // 启动 protocol
        protocolHandler.start();
    } catch (Exception e) {
        ...
    }
}

Http11NioProtocol.png
ProtocolHandler是一个接口,start()方法有两个类实现了:AbstractProtocolAbstractAjpProtocol
从上图UML图中知道,Http11NioProtocol继承自AbstractProtocol,所以 protocolHandler.start()会调用AbstractProtocolstart()方法。

10.AbstractProtocol.start()

先看一下AbstractProtocol的代码结构: connector的结构.png
connector的结构图2.png

public void start() throws Exception {
    ...
    // 启动EndPoint
    endpoint.start();
    // 启动超时线程
    asyncTimeout = new AsyncTimeout();
    Thread timeoutThread = new Thread(asyncTimeout, getNameInternal() + "-AsyncTimeout");
    int priority = endpoint.getThreadPriority();
    if (priority < Thread.MIN_PRIORITY || priority > Thread.MAX_PRIORITY) {
        priority = Thread.NORM_PRIORITY;
    }
    timeoutThread.setPriority(priority);
    timeoutThread.setDaemon(true);
    timeoutThread.start();
}

AbstractEndpoint.start()

public final void start() throws Exception {
    if (bindState == BindState.UNBOUND) {
        bindWithCleanup();
        bindState = BindState.BOUND_ON_START;
    }
    // 调用内部的抽象方法,方法由子类实现,即:NioEndpoint.startInternal()
    startInternal();
}

11.NioEndpoint.startInternal()

public void startInternal() throws Exception {
    if (!running) {
        ...
        // 启动Poller线程,后台一直运行着,后续用来处理HTTP请求的socket
        poller = new Poller();
        Thread pollerThread = new Thread(poller, getName() + "-Poller");
        pollerThread.setPriority(threadPriority);
        pollerThread.setDaemon(true);
        pollerThread.start();
        // 启动Acceptor线程,后台一直运行着,后续用来接收HTTP请求的socket
        startAcceptorThread();
    }
}

至此EndPoint启动完毕后Connector启动也就完成了,一个Service启动完成了,如果有多个service,则所有的Service启动都走相同的流程。当所有的Service都启动完了,Server也就启动完成。此时整个Tomcat启动完毕。