zoukankan      html  css  js  c++  java
  • Tomcat的启动流程

    一、Lifecycle

     tomcat启动,实际上就是对以上的组件进行实例化,因此使用Lifecycle接口统一管理各组件的生命周期,根据各个组件之间的父子级关系,首先调用init()方法逐级初始化各组件,然后在调用start()的方法进行启动。

        //初始化
        public void init() throws LifecycleException;
        //启动
        public void start() throws LifecycleException;
        //停止
        public void stop() throws LifecycleException;
        //销毁
        public void destroy() throws LifecycleException;

    tomcat中的这些组件也会继承Lifecycle,由子类再去实现这些方法。

     二、startup.sh

    os400=false
    case "`uname`" in
    OS400*) os400=true;;
    esac
    
    # resolve links - $0 may be a softlink
    PRG="$0"
    
    while [ -h "$PRG" ] ; do
      ls=`ls -ld "$PRG"`
      link=`expr "$ls" : '.*-> (.*)$'`
      if expr "$link" : '/.*' > /dev/null; then
        PRG="$link"
      else
        PRG=`dirname "$PRG"`/"$link"
      fi
    done
    
    PRGDIR=`dirname "$PRG"`
    EXECUTABLE=catalina.sh
    
    # Check that target executable exists
    if $os400; then
      # -x will Only work on the os400 if the files are:
      # 1. owned by the user
      # 2. owned by the PRIMARY group of the user
      # this will not work if the user belongs in secondary groups
      eval
    else
      if [ ! -x "$PRGDIR"/"$EXECUTABLE" ]; then
        echo "Cannot find $PRGDIR/$EXECUTABLE"
        echo "The file is absent or does not have execute permission"
        echo "This file is needed to run this program"
        exit 1
      fi
    fi
    
    exec "$PRGDIR"/"$EXECUTABLE" start "$@"

    我们启动tomcat的时候会使用startup.sh,看到shell脚本的最后一行,意思就是执行$EXECUTABLE变量(对应的是catalina.sh)并传入参数start,之后就是执行java xxxx.jar org.apache.catalina.startup.Bootstrap start命令。

    四、Bootstrap

        private static volatile Bootstrap daemon = null;
        private static final Object daemonLock = new Object();
        
        public static void main(String args[]) {
    
            synchronized (daemonLock) {
                if (daemon == null) {
                    // Don't set daemon until init() has completed
                    //实例化Bootstrap
                    Bootstrap bootstrap = new Bootstrap();
                    try {
                        //调用初始化方法
                        bootstrap.init();
                    } catch (Throwable t) {
                        handleThrowable(t);
                        t.printStackTrace();
                        return;
                    }
                    //赋值给daemon
                    daemon = bootstrap;
                } else {
                    Thread.currentThread().setContextClassLoader(daemon.catalinaLoader);
                }
            }
    
            try {
                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")) {
                    //tomcat启动时传入的值时start,因此启动走此分支
                    daemon.setAwait(true);
                    //加载初始化
                    daemon.load(args);
                    //启动
                    daemon.start();
                    if (null == daemon.getServer()) {
                        System.exit(1);
                    }
                } 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.");
                }
            } catch (Throwable t) {
                // Unwrap the Exception for clearer error reporting
                if (t instanceof InvocationTargetException &&
                        t.getCause() != null) {
                    t = t.getCause();
                }
                handleThrowable(t);
                t.printStackTrace();
                System.exit(1);
            }
        }

     init方法(Bootstrap)

        public void init() throws Exception {
            //初始化类加载器
            initClassLoaders();
            
            Thread.currentThread().setContextClassLoader(catalinaLoader);
    
            SecurityClassLoad.securityClassLoad(catalinaLoader);
    
            // Load our startup class and call its process() method
            if (log.isDebugEnabled()) {
                log.debug("Loading startup class");
            }
            //实例化Catalina对象
            Class<?> startupClass = catalinaLoader.loadClass("org.apache.catalina.startup.Catalina");
            Object startupInstance = startupClass.getConstructor().newInstance();
    
            // Set the shared extensions class loader
            if (log.isDebugEnabled()) {
                log.debug("Setting startup class properties");
            }
            String methodName = "setParentClassLoader";
            Class<?> paramTypes[] = new Class[1];
            paramTypes[0] = Class.forName("java.lang.ClassLoader");
            Object paramValues[] = new Object[1];
            paramValues[0] = sharedLoader;
            //反射调用Catalina的setParentClassLoader方法
            Method method =
                startupInstance.getClass().getMethod(methodName, paramTypes);
            method.invoke(startupInstance, paramValues);
            //赋值给catalinaDaemon
            catalinaDaemon = startupInstance;
        }

    load和start方法(Bootstrap)

        private void load(String[] arguments) throws Exception {
    
            // Call the load() method
            String methodName = "load";
            Object param[];
            Class<?> paramTypes[];
            if (arguments==null || arguments.length==0) {
                paramTypes = null;
                param = null;
            } else {
                paramTypes = new Class[1];
                paramTypes[0] = arguments.getClass();
                param = new Object[1];
                param[0] = arguments;
            }
            Method method =
                catalinaDaemon.getClass().getMethod(methodName, paramTypes);
            if (log.isDebugEnabled()) {
                log.debug("Calling startup class " + method);
            }
            //反射调用Catalina的load方法
            method.invoke(catalinaDaemon, param);
        }
        
            public void start() throws Exception {
            if (catalinaDaemon == null) {
                init();
            }
            //反射调用Catalina的start方法
            Method method = catalinaDaemon.getClass().getMethod("start", (Class [])null);
            method.invoke(catalinaDaemon, (Object [])null);
        }

    五、Catalina

    load方法

        public void load() {
    
            if (loaded) {
                return;
            }
            loaded = true;
    
            long t1 = System.nanoTime();
    
            initDirs();
    
            // Before digester - it may be needed
            initNaming();
    
            //创建Digester对象,用于解析server.xml文件
            Digester digester = createStartDigester();
    
            InputSource inputSource = null;
            InputStream inputStream = null;
            File file = null;
            try {
                try {
                    //定位到配置文件server.xml
                    file = configFile();
                    inputStream = new FileInputStream(file);
                    inputSource = new InputSource(file.toURI().toURL().toString());
                } catch (Exception e) {
                    if (log.isDebugEnabled()) {
                        log.debug(sm.getString("catalina.configFail", file), e);
                    }
                }
                if (inputStream == null) {
                    try {
                        inputStream = getClass().getClassLoader()
                            .getResourceAsStream(getConfigFile());
                        inputSource = new InputSource
                            (getClass().getClassLoader()
                             .getResource(getConfigFile()).toString());
                    } catch (Exception e) {
                        if (log.isDebugEnabled()) {
                            log.debug(sm.getString("catalina.configFail",
                                    getConfigFile()), e);
                        }
                    }
                }
    
                // This should be included in catalina.jar
                // Alternative: don't bother with xml, just create it manually.
                if (inputStream == null) {
                    try {
                        inputStream = getClass().getClassLoader()
                                .getResourceAsStream("server-embed.xml");
                        inputSource = new InputSource
                        (getClass().getClassLoader()
                                .getResource("server-embed.xml").toString());
                    } catch (Exception e) {
                        if (log.isDebugEnabled()) {
                            log.debug(sm.getString("catalina.configFail",
                                    "server-embed.xml"), e);
                        }
                    }
                }
    
    
                if (inputStream == null || inputSource == null) {
                    if  (file == null) {
                        log.warn(sm.getString("catalina.configFail",
                                getConfigFile() + "] or [server-embed.xml]"));
                    } else {
                        log.warn(sm.getString("catalina.configFail",
                                file.getAbsolutePath()));
                        if (file.exists() && !file.canRead()) {
                            log.warn("Permissions incorrect, read permission is not allowed on the file.");
                        }
                    }
                    return;
                }
    
                try {
                    inputSource.setByteStream(inputStream);
                    digester.push(this);
                    //解析配置文件server.xml
                    digester.parse(inputSource);
                } catch (SAXParseException spe) {
                    log.warn("Catalina.start using " + getConfigFile() + ": " +
                            spe.getMessage());
                    return;
                } catch (Exception e) {
                    log.warn("Catalina.start using " + getConfigFile() + ": " , e);
                    return;
                }
            } finally {
                if (inputStream != null) {
                    try {
                        inputStream.close();
                    } catch (IOException e) {
                        // Ignore
                    }
                }
            }
    
            getServer().setCatalina(this);
            getServer().setCatalinaHome(Bootstrap.getCatalinaHomeFile());
            getServer().setCatalinaBase(Bootstrap.getCatalinaBaseFile());
    
            // Stream redirection
            initStreams();
    
            // Start the new server
            try {
                //调用server对象的init方法
                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);
                }
            }
    
            long t2 = System.nanoTime();
            if(log.isInfoEnabled()) {
                log.info("Initialization processed in " + ((t2 - t1) / 1000000) + " ms");
            }
        }
    
        public Object parse(InputSource input) throws IOException, SAXException {
            configure();
            getXMLReader().parse(input);
            //返回的root就是Catalina对象,并且实例化了Server(StandardServer对象,包含了server以下的service,connector等实例对象)赋值给Catalina的server属性
            return root;
        }

    StandardServer继承了LifecycleMBeanBase->LifecycleBase,因此调用server的init方法,就是调用LifecycleBase的init方法

     public final synchronized void init() throws LifecycleException {
            if (!state.equals(LifecycleState.NEW)) {
                invalidTransition(Lifecycle.BEFORE_INIT_EVENT);
            }
    
            try {
                setStateInternal(LifecycleState.INITIALIZING, null, false);
                //init的关键方法,设计模式模板方法的应用,会调用子类StandardServer的initInternal方法
                initInternal();
                setStateInternal(LifecycleState.INITIALIZED, null, false);
            } catch (Throwable t) {
                handleSubClassException(t, "lifecycleBase.initFail", toString());
            }
        }
        //server容器初始化
        protected void initInternal() throws LifecycleException {
    
            super.initInternal();
    
            // Register global String cache
            // Note although the cache is global, if there are multiple Servers
            // present in the JVM (may happen when embedding) then the same cache
            // will be registered under multiple names
            onameStringCache = register(new StringCache(), "type=StringCache");
    
            // Register the MBeanFactory
            MBeanFactory factory = new MBeanFactory();
            factory.setContainer(this);
            onameMBeanFactory = register(factory, "type=MBeanFactory");
    
            // Register the naming resources
            globalNamingResources.init();
    
            // Populate the extension validator with JARs from common and shared
            // class loaders
            if (getCatalina() != null) {
                ClassLoader cl = getCatalina().getParentClassLoader();
                // Walk the class loader hierarchy. Stop at the system class loader.
                // This will add the shared (if present) and common class loaders
                while (cl != null && cl != ClassLoader.getSystemClassLoader()) {
                    if (cl instanceof URLClassLoader) {
                        URL[] urls = ((URLClassLoader) cl).getURLs();
                        for (URL url : urls) {
                            if (url.getProtocol().equals("file")) {
                                try {
                                    File f = new File (url.toURI());
                                    if (f.isFile() &&
                                            f.getName().endsWith(".jar")) {
                                        ExtensionValidator.addSystemResource(f);
                                    }
                                } catch (URISyntaxException | IOException e) {
                                    // Ignore
                                }
                            }
                        }
                    }
                    cl = cl.getParent();
                }
            }
            // Initialize our defined Services
            //初始化service容器
            for (Service service : services) {
                //重复sever的init过程,只不过这次是调用StandardService的initInternal方法
                service.init();
            }
        }

    service容器初始化

    //service容器初始化
        protected void initInternal() throws LifecycleException {
    
            super.initInternal();
    
            if (engine != null) {
                //engine容器的初始化,调用StandardEngine的initInternal方法
                engine.init();
            }
    
            // Initialize any Executors
            for (Executor executor : findExecutors()) {
                if (executor instanceof JmxEnabled) {
                    ((JmxEnabled) executor).setDomain(getDomain());
                }
                executor.init();
            }
    
            // Initialize mapper listener
            mapperListener.init();
    
            // Initialize our defined Connectors
            synchronized (connectorsLock) {
                for (Connector connector : connectors) {
                    try {
                        //连接器的初始化
                        connector.init();
                    } catch (Exception e) {
                        String message = sm.getString(
                                "standardService.connector.initFailed", connector);
                        log.error(message, e);
    
                        if (Boolean.getBoolean("org.apache.catalina.startup.EXIT_ON_INIT_FAILURE")) {
                            throw new LifecycleException(message);
                        }
                    }
                }
            }
        }

    engine容器的初始化

    //engine容器的初始化
        protected void initInternal() throws LifecycleException {
            // Ensure that a Realm is present before any attempt is made to start
            // one. This will create the default NullRealm if necessary.
            getRealm();
            //调用父类ContainerBase的初始化方法
            super.initInternal();
        }
        //engine初始化创建了一个线程池,在engine组件start阶段使用
        protected void initInternal() throws LifecycleException {
            BlockingQueue<Runnable> startStopQueue = new LinkedBlockingQueue<>();
            startStopExecutor = new ThreadPoolExecutor(
                    getStartStopThreadsInternal(),
                    getStartStopThreadsInternal(), 10, TimeUnit.SECONDS,
                    startStopQueue,
                    new StartStopThreadFactory(getName() + "-startStop-"));
            startStopExecutor.allowCoreThreadTimeOut(true);
            super.initInternal();
        }

    连接器Connector的初始化

    protected void initInternal() throws LifecycleException {
    
            super.initInternal();
            
            //适配器的初始化,为了完成请求HttpRequest到HttpServletRequest的转换
            adapter = new CoyoteAdapter(this);
            protocolHandler.setAdapter(adapter);
    
            // Make sure parseBodyMethodsSet has a default
            if (null == parseBodyMethodsSet) {
                setParseBodyMethods(getParseBodyMethods());
            }
    
            if (protocolHandler.isAprRequired() && !AprLifecycleListener.isInstanceCreated()) {
                throw new LifecycleException(sm.getString("coyoteConnector.protocolHandlerNoAprListener",
                        getProtocolHandlerClassName()));
            }
            if (protocolHandler.isAprRequired() && !AprLifecycleListener.isAprAvailable()) {
                throw new LifecycleException(sm.getString("coyoteConnector.protocolHandlerNoAprLibrary",
                        getProtocolHandlerClassName()));
            }
            if (AprLifecycleListener.isAprAvailable() && AprLifecycleListener.getUseOpenSSL() &&
                    protocolHandler instanceof AbstractHttp11JsseProtocol) {
                AbstractHttp11JsseProtocol<?> jsseProtocolHandler =
                        (AbstractHttp11JsseProtocol<?>) protocolHandler;
                if (jsseProtocolHandler.isSSLEnabled() &&
                        jsseProtocolHandler.getSslImplementationName() == null) {
                    // OpenSSL is compatible with the JSSE configuration, so use it if APR is available
                    jsseProtocolHandler.setSslImplementationName(OpenSSLImplementation.class.getName());
                }
            }
    
            try {
                //协议处理器protocolHandler的初始化,主要是其内部Endpoint的初始化
                protocolHandler.init();
            } catch (Exception e) {
                throw new LifecycleException(
                        sm.getString("coyoteConnector.protocolHandlerInitializationFailed"), e);
            }
        }

    协议处理器protocolHandler初始化

     public void init() throws Exception {
            // Upgrade protocols have to be configured first since the endpoint
            // init (triggered via super.init() below) uses this list to configure
            // the list of ALPN protocols to advertise
            for (UpgradeProtocol upgradeProtocol : upgradeProtocols) {
                configureUpgradeProtocol(upgradeProtocol);
            }
    
            super.init();
    
            // Set the Http11Protocol (i.e. this) for any upgrade protocols once
            // this has completed initialisation as the upgrade protocols may expect this
            // to be initialised when the call is made
            for (UpgradeProtocol upgradeProtocol : upgradeProtocols) {
                if (upgradeProtocol instanceof Http2Protocol) {
                    ((Http2Protocol) upgradeProtocol).setHttp11Protocol(this);
                }
            }
        }
    
        public void init() throws Exception {
            if (getLog().isInfoEnabled()) {
                getLog().info(sm.getString("abstractProtocolHandler.init", getName()));
            }
    
            if (oname == null) {
                // Component not pre-registered so register it
                oname = createObjectName();
                if (oname != null) {
                    Registry.getRegistry(null, null).registerComponent(this, oname, null);
                }
            }
    
            if (this.domain != null) {
                ObjectName rgOname = new ObjectName(domain + ":type=GlobalRequestProcessor,name=" + getName());
                this.rgOname = rgOname;
                Registry.getRegistry(null, null).registerComponent(
                        getHandler().getGlobal(), rgOname, null);
            }
    
            String endpointName = getName();
            endpoint.setName(endpointName.substring(1, endpointName.length()-1));
            endpoint.setDomain(domain);
            //通信断点的初始化
            endpoint.init();
        }
        //AbstractEndpoint
        public void init() throws Exception {
            if (bindOnInit) {
                //重要
                bind();
                bindState = BindState.BOUND_ON_INIT;
            }
            if (this.domain != null) {
                // Register endpoint (as ThreadPool - historical name)
                oname = new ObjectName(domain + ":type=ThreadPool,name="" + getName() + """);
                Registry.getRegistry(null, null).registerComponent(this, oname, null);
    
                ObjectName socketPropertiesOname = new ObjectName(domain +
                        ":type=SocketProperties,name="" + getName() + """);
                socketProperties.setObjectName(socketPropertiesOname);
                Registry.getRegistry(null, null).registerComponent(socketProperties, socketPropertiesOname, null);
    
                for (SSLHostConfig sslHostConfig : findSslHostConfigs()) {
                    registerJmx(sslHostConfig);
                }
            }
        }
        
        //NioEndpoint类
        public void bind() throws Exception {
    
            if (!getUseInheritedChannel()) {
                //获取nio通道channel,tomcat8之后默认就是nio
                serverSock = ServerSocketChannel.open();
                socketProperties.setProperties(serverSock.socket());
                InetSocketAddress addr = (getAddress()!=null?new InetSocketAddress(getAddress(),getPort()):new InetSocketAddress(getPort()));
                //绑定端口,但尚未使用accept获取客户端连接
                serverSock.socket().bind(addr,getAcceptCount());
            } else {
                // Retrieve the channel provided by the OS
                Channel ic = System.inheritedChannel();
                if (ic instanceof ServerSocketChannel) {
                    serverSock = (ServerSocketChannel) ic;
                }
                if (serverSock == null) {
                    throw new IllegalArgumentException(sm.getString("endpoint.init.bind.inherited"));
                }
            }
            //设置为阻塞模式
            serverSock.configureBlocking(true); //mimic APR behavior
    
            // Initialize thread count defaults for acceptor, poller
            if (acceptorThreadCount == 0) {
                // FIXME: Doesn't seem to work that well with multiple accept threads
                acceptorThreadCount = 1;
            }
            if (pollerThreadCount <= 0) {
                //minimum one poller thread
                pollerThreadCount = 1;
            }
            setStopLatch(new CountDownLatch(pollerThreadCount));
    
            // 初始化SSL
            initialiseSsl();
         //初始化BlockPoller线程并启动
            selectorPool.open();
        }

    start方法

    public void start() {
    
            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 {
                //最终调用的是StandardServer的startInternal方法
                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();
                }
                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) {
                await();
                stop();
            }
        }

    start方法采用的和init方法一样的设计模式,因此也是调用各个组件的startInternal方法,完成启动。

    StandardServer的启动

        //StandardServer
        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
                    service.start();
                }
            }
        }

    StandardService的启动

    //StandardService
        protected void startInternal() throws LifecycleException {
    
            if(log.isInfoEnabled()) {
                log.info(sm.getString("standardService.start.name", this.name));
            }
            setState(LifecycleState.STARTING);
    
            // Start our defined Container first
            if (engine != null) {
                synchronized (engine) {
                    //启动engine
                    engine.start();
                }
            }
    
            synchronized (executors) {
                for (Executor executor: executors) {
                    executor.start();
                }
            }
    
            mapperListener.start();
    
            // Start our defined Connectors second
            synchronized (connectorsLock) {
                for (Connector connector: connectors) {
                    try {
                        // If it has already failed, don't try and start it
                        if (connector.getState() != LifecycleState.FAILED) {
                            //启动connector
                            connector.start();
                        }
                    } catch (Exception e) {
                        log.error(sm.getString(
                                "standardService.connector.startFailed",
                                connector), e);
                    }
                }
            }
        }

    StandardEngine的启动

        //StandardEngine
        protected synchronized void startInternal() throws LifecycleException {
    
            // Log our server identification information
            if (log.isInfoEnabled()) {
                log.info(sm.getString("standardEngine.start", ServerInfo.getServerInfo()));
            }
    
            // Standard container startup
            super.startInternal();
        }    
        //ContainerBase
        protected synchronized void startInternal() throws LifecycleException {
    
            // Start our subordinate components, if any
            logger = null;
            getLogger();
            Cluster cluster = getClusterInternal();
            if (cluster instanceof Lifecycle) {
                ((Lifecycle) cluster).start();
            }
            Realm realm = getRealmInternal();
            if (realm instanceof Lifecycle) {
                ((Lifecycle) realm).start();
            }
    
            //查找子容器,启动子容器,host在初始化阶段后还是不完整的需要继续封装你,把容器关系维护完整
            Container children[] = findChildren();
            List<Future<Void>> results = new ArrayList<>();
            for (Container child : children) {+-
                //在init阶段初始化的线程池,现在开始提交任务执行
                results.add(startStopExecutor.submit(new StartChild(child)));
            }
    
            MultiThrowable multiThrowable = null;
    
            for (Future<Void> result : results) {
                try {
                    result.get();
                } catch (Throwable e) {
                    log.error(sm.getString("containerBase.threadedStartFailed"), e);
                    if (multiThrowable == null) {
                        multiThrowable = new MultiThrowable();
                    }
                    multiThrowable.add(e);
                }
    
            }
            if (multiThrowable != null) {
                throw new LifecycleException(sm.getString("containerBase.threadedStartFailed"),
                        multiThrowable.getThrowable());
            }
    
            // Start the Valves in our pipeline (including the basic), if any
            if (pipeline instanceof Lifecycle) {
                ((Lifecycle) pipeline).start();
            }
            //设置生命周期容器状态
            setState(LifecycleState.STARTING);
    
            // Start our thread
            threadStart();
        }

    在init方法里,容器的初始化只执行到了Engine,剩下的容器初始化交给了在engine初始化方法里初始化的线程池来进行。进入ContainerBase的内部类StartChild的call方法,接着调用child.start(),最终调用StandardHost的startInternal方法。

        //StandardHost
        protected synchronized void startInternal() throws LifecycleException {
    
            // Set error report valve
            String errorValve = getErrorReportValveClass();
            if ((errorValve != null) && (!errorValve.equals(""))) {
                try {
                    boolean found = false;
                    Valve[] valves = getPipeline().getValves();
                    for (Valve valve : valves) {
                        if (errorValve.equals(valve.getClass().getName())) {
                            found = true;
                            break;
                        }
                    }
                    if(!found) {
                        Valve valve =
                            (Valve) Class.forName(errorValve).getConstructor().newInstance();
                        getPipeline().addValve(valve);
                    }
                } catch (Throwable t) {
                    ExceptionUtils.handleThrowable(t);
                    log.error(sm.getString(
                            "standardHost.invalidErrorReportValveClass",
                            errorValve), t);
                }
            }
            //调用ContainerBase的startInternal方法
            super.startInternal();
        }

    子线程再次进入ContainerBase的startInternal方法,这次findChildren()不会再次获得子容器,会接着往下,执行setState(LifecycleState.STARTING)方法,设置生命周期状态。

        //LifecycleBase
        protected synchronized void setState(LifecycleState state) throws LifecycleException {
            setStateInternal(state, null, true);
        }
        //LifecycleBase    
        private synchronized void setStateInternal(LifecycleState state, Object data, boolean check)
                throws LifecycleException {
            //省略代码
            ···
    
            this.state = state;
            String lifecycleEvent = state.getLifecycleEvent();
            if (lifecycleEvent != null) {
                //触发生命周期事件
                fireLifecycleEvent(lifecycleEvent, data);
            }
        }
        //LifecycleBase    
        protected void fireLifecycleEvent(String type, Object data) {
            LifecycleEvent event = new LifecycleEvent(this, type, data);
            for (LifecycleListener listener : lifecycleListeners) {
                //往监听器里添加事件
                listener.lifecycleEvent(event);
            }
        }

    Host的实例化,是通过设置生命周期状态(start),通过触发host的生命周期事件fireLifecycleEvent来执行后续(还会接着实例化host下面的容器:context等)的工作,在Hostconfig(生命周期监听器)中完成。

        //HostConfig
        public void lifecycleEvent(LifecycleEvent event) {
    
            // Identify the host we are associated with
            try {
                host = (Host) event.getLifecycle();
                if (host instanceof StandardHost) {
                    setCopyXML(((StandardHost) host).isCopyXML());
                    setDeployXML(((StandardHost) host).isDeployXML());
                    setUnpackWARs(((StandardHost) host).isUnpackWARs());
                    setContextClass(((StandardHost) host).getContextClass());
                }
            } catch (ClassCastException e) {
                log.error(sm.getString("hostConfig.cce", event.getLifecycle()), e);
                return;
            }
    
            // Process the event that has occurred
            if (event.getType().equals(Lifecycle.PERIODIC_EVENT)) {
                check();
            } else if (event.getType().equals(Lifecycle.BEFORE_START_EVENT)) {
                beforeStart();
            } else if (event.getType().equals(Lifecycle.START_EVENT)) {
                //会执行此方法
                start();
            } else if (event.getType().equals(Lifecycle.STOP_EVENT)) {
                stop();
            }
        }
    
        public void start() {
            
            ···
            
            //部署app应用
            if (host.getDeployOnStartup()) {
                deployApps();
            }
        }
        //发布应用
        protected void deployApps() {
            File appBase = host.getAppBaseFile();
            File configBase = host.getConfigBaseFile();
            String[] filteredAppPaths = filterAppPaths(appBase.list());
            // XML描述的方式
            deployDescriptors(configBase, configBase.list());
            // WAR包的方式
            deployWARs(appBase, filteredAppPaths);
            // 文件夹的方式
            deployDirectories(appBase, filteredAppPaths);
        }

    以文件夹的方式为例

        protected void deployDirectories(File appBase, String[] files) {
    
            if (files == null) {
                return;
            }
            //创建了一个线程池
            ExecutorService es = host.getStartStopExecutor();
            List<Future<?>> results = new ArrayList<>();
    
            for (String file : files) {
                if (file.equalsIgnoreCase("META-INF")) {
                    continue;
                }
                if (file.equalsIgnoreCase("WEB-INF")) {
                    continue;
                }
    
                File dir = new File(appBase, file);
                if (dir.isDirectory()) {
                    ContextName cn = new ContextName(file, false);
    
                    if (tryAddServiced(cn.getName())) {
                        try {
                            if (deploymentExists(cn.getName())) {
                                removeServiced(cn.getName());
                                continue;
                            }
    
                            // 把context的创建和start以线程的方式提交
                            results.add(es.submit(new DeployDirectory(this, cn, dir)));
                        } catch (Throwable t) {
                            ExceptionUtils.handleThrowable(t);
                            removeServiced(cn.getName());
                            throw t;
                        }
                    }
                }
            }
    
            for (Future<?> result : results) {
                try {
                    result.get();
                } catch (Exception e) {
                    log.error(sm.getString("hostConfig.deployDir.threaded.error"), e);
                }
            }
        }
        //DeployDirectory
            public void run() {
                try {
                    config.deployDirectory(cn, dir);
                } finally {
                    config.removeServiced(cn.getName());
                }
            }
        //HostConfig
        protected void deployDirectory(ContextName cn, File dir) {
    
            ···
    
            try {
                if (deployThisXML && xml.exists()) {
                    synchronized (digesterLock) {
                        try {
                            //通过xml解析获取Context对象
                            context = (Context) digester.parse(xml);
                        } catch (Exception e) {
                            log.error(sm.getString("hostConfig.deployDescriptor.error", xml), e);
                            context = new FailedContext();
                        } finally {
                            digester.reset();
                            if (context == null) {
                                context = new FailedContext();
                            }
                        }
                    }
    
                    if (copyThisXml == false && context instanceof StandardContext) {
                        // Host is using default value. Context may override it.
                        copyThisXml = ((StandardContext) context).getCopyXML();
                    }
    
                    if (copyThisXml) {
                        Files.copy(xml.toPath(), xmlCopy.toPath());
                        context.setConfigFile(xmlCopy.toURI().toURL());
                    } else {
                        context.setConfigFile(xml.toURI().toURL());
                    }
                } else if (!deployThisXML && xml.exists()) {
                    // Block deployment as META-INF/context.xml may contain security
                    // configuration necessary for a secure deployment.
                    log.error(sm.getString("hostConfig.deployDescriptor.blocked", cn.getPath(), xml, xmlCopy));
                    context = new FailedContext();
                } else {
                    context = (Context) Class.forName(contextClass).getConstructor().newInstance();
                }
    
                Class<?> clazz = Class.forName(host.getConfigClass());
                LifecycleListener listener = (LifecycleListener) clazz.getConstructor().newInstance();
                context.addLifecycleListener(listener);
    
                context.setName(cn.getName());
                context.setPath(cn.getPath());
                context.setWebappVersion(cn.getVersion());
                context.setDocBase(cn.getBaseName());
                //添加到host容器中,此时context还是不完整的,需要进一步封装wrapper(servlet)
                host.addChild(context);
            } catch (Throwable t) {
                ExceptionUtils.handleThrowable(t);
                log.error(sm.getString("hostConfig.deployDir.error", dir.getAbsolutePath()), t);
            } finally {
                ···
            }
    
            deployed.put(cn.getName(), deployedApp);
    
            if( log.isInfoEnabled() ) {
                log.info(sm.getString("hostConfig.deployDir.finished",
                        dir.getAbsolutePath(), Long.valueOf(System.currentTimeMillis() - startTime)));
            }
        }

    host.addChild(context)时才触发context实例核心内容

        //StandardHost
        public void addChild(Container child) {
            
            ···
            
            //调用父类
            super.addChild(child);
    
        }
        //ContainerBase
        public void addChild(Container child) {
            if (Globals.IS_SECURITY_ENABLED) {
                PrivilegedAction<Void> dp =
                    new PrivilegedAddChild(child);
                AccessController.doPrivileged(dp);
            } else {
                addChildInternal(child);
            }
        }
        
        private void addChildInternal(Container child) {
    
            ···
    
            // Start child
            // Don't do this inside sync block - start can be a slow process and
            // locking the children object can cause problems elsewhere
            try {
                if ((getState().isAvailable() ||
                        LifecycleState.STARTING_PREP.equals(getState())) &&
                        startChildren) {
                    //这个child就是StandardContext,接着依然通过父类调用到StandardContext的startInternal方法
                    child.start();
                }
            } catch (LifecycleException e) {
                log.error("ContainerBase.addChild: start: ", e);
                throw new IllegalStateException(sm.getString("containerBase.child.start"), e);
            } finally {
                fireContainerEvent(ADD_CHILD_EVENT, child);
            }
        }

    context具体读取web.xml封装wrapper过程也是使用了事件驱动机制,往监听器添加了一个事件,交给ContextConfig执行。

        protected synchronized void startInternal() throws LifecycleException {
    
            ···
    
            // 创建工作目录,tomcat下的work目录
            postWorkDirectory();
    
            ···
    
            if (getLoader() == null) {
                //web应用类加载器,每个Context都会设置一个
                WebappLoader webappLoader = new WebappLoader();
                webappLoader.setDelegate(getDelegate());
                setLoader(webappLoader);
            }
    
            ···
    
                    // 发出生命周期事件,调度了ContextConfig,读取web.xml,这里就是读取某一个项目的web.xml内容
                    fireLifecycleEvent(Lifecycle.CONFIGURE_START_EVENT, null);
    
                    ···
    
                // 加载初始化servlet(只是加载了servlet的全限定类名)
                if (ok) {
                    //loadOnStartup才开始根据servlet的全限定类名初始化servlet
                    if (!loadOnStartup(findChildren())){
                        log.error(sm.getString("standardContext.servletFail"));
                        ok = false;
                    }
                }
    
            ···
        }
        
        public boolean loadOnStartup(Container children[]) {
    
            ···
    
            // Load the collected "load on startup" servlets
            for (ArrayList<Wrapper> list : map.values()) {
                for (Wrapper wrapper : list) {
                    try {
                        //实例化servlet
                        wrapper.load();
                    } catch (ServletException e) {
                        getLogger().error(sm.getString("standardContext.loadOnStartup.loadException",
                              getName(), wrapper.getName()), StandardWrapper.getRootCause(e));
                        // NOTE: load errors (including a servlet that throws
                        // UnavailableException from the init() method) are NOT
                        // fatal to application startup
                        // unless failCtxIfServletStartFails="true" is specified
                        if(getComputedFailCtxIfServletStartFails()) {
                            return false;
                        }
                    }
                }
            }
            return true;
    
        }
    
        public synchronized void load() throws ServletException {
            //反射获取了servlet的实例
            instance = loadServlet();
    
            ···
        }

     Connector的启动,在StandardService的启动的时候先启动的Engine,然后遍历调用connector.start(),启动connector。

        protected void startInternal() throws LifecycleException {
    
            // Validate settings before starting
            if (getPort() < 0) {
                throw new LifecycleException(sm.getString(
                        "coyoteConnector.invalidPort", Integer.valueOf(getPort())));
            }
    
            setState(LifecycleState.STARTING);
    
            try {
                //关键点,协议处理器的启动
                protocolHandler.start();
            } catch (Exception e) {
                throw new LifecycleException(
                        sm.getString("coyoteConnector.protocolHandlerStartFailed"), e);
            }
        }
        
        public void start() throws Exception {
            if (getLog().isInfoEnabled()) {
                getLog().info(sm.getString("abstractProtocolHandler.start", getName()));
            }
            //启动endpiont
            endpoint.start();
    
            // Start timeout thread
            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();
        }
        
        public final void start() throws Exception {
            if (bindState == BindState.UNBOUND) {
                bind();
                bindState = BindState.BOUND_ON_START;
            }
            startInternal();
        }
        //NioEndpoint
        public void startInternal() throws Exception {
    
            if (!running) {
                running = true;
                paused = false;
    
                processorCache = new SynchronizedStack<>(SynchronizedStack.DEFAULT_SIZE,
                        socketProperties.getProcessorCache());
                eventCache = new SynchronizedStack<>(SynchronizedStack.DEFAULT_SIZE,
                                socketProperties.getEventCache());
                nioChannels = new SynchronizedStack<>(SynchronizedStack.DEFAULT_SIZE,
                        socketProperties.getBufferPool());
    
                // Create worker collection
                if (getExecutor() == null) {
                    createExecutor();
                }
    
                initializeConnectionLatch();
    
                // NIO模型 创建poller线程并启动
                pollers = new Poller[getPollerThreadCount()];
                for (int i=0; i<pollers.length; i++) {
                    pollers[i] = new Poller();
                    Thread pollerThread = new Thread(pollers[i], getName() + "-ClientPoller-"+i);
                    pollerThread.setPriority(threadPriority);
                    pollerThread.setDaemon(true);
                    pollerThread.start();
                }
                //启动acceptor线程 
                startAcceptorThreads();
            }
        }
    
        protected final void startAcceptorThreads() {
            int count = getAcceptorThreadCount();
            acceptors = new Acceptor[count];
    
            for (int i = 0; i < count; i++) {
                acceptors[i] = createAcceptor();
                String threadName = getName() + "-Acceptor-" + i;
                acceptors[i].setThreadName(threadName);
                Thread t = new Thread(acceptors[i], threadName);
                t.setPriority(getAcceptorThreadPriority());
                t.setDaemon(getDaemon());
                t.start();
            }
        }

    启动acceptor线程

    public class NioEndpoint extends AbstractJsseEndpoint<NioChannel> {
    
        private volatile ServerSocketChannel serverSock = null;
    
        protected class
            Acceptor extends AbstractEndpoint.Acceptor {
    
            @Override
            public void run() {
    
                int errorDelay = 0;
    
                // Loop until we receive a shutdown command
                while (running) {
    
                    // Loop if endpoint is paused
                    while (paused && running) {
                        state = AcceptorState.PAUSED;
                        try {
                            Thread.sleep(50);
                        } catch (InterruptedException e) {
                            // Ignore
                        }
                    }
    
                    if (!running) {
                        break;
                    }
                    state = AcceptorState.RUNNING;
    
                    try {
                        //if we have reached max connections, wait
                        countUpOrAwaitConnection();
    
                        SocketChannel socket = null;
                        try {
                            // 获取socket连接
                            socket = serverSock.accept();
                        } catch (IOException ioe) {
                            ···
                        }
                        ···
                    } catch (Throwable t) {
                        ···
                    }
                }
                state = AcceptorState.ENDED;
            }
            
            ···
            
        }
    }

    到此,tomecat的初始化工作就完成了,Acceptor线程会阻塞在socket = serverSock.accept()方法上,等待客户端的连接。

  • 相关阅读:
    DropDownList判断值是否存在下拉列表中
    postgre教程
    Cookie seesion 赋值
    Winform定时启动
    ASP.NET数据绑定控件
    ASP.NET常用数据绑定控件优劣总结
    Cards and Joy (dp好题)
    River Hopscotch (二分)
    剪花布条(KMP入门)
    GCD (区间数的质因子打表+容斥原理)
  • 原文地址:https://www.cnblogs.com/sglx/p/15410859.html
Copyright © 2011-2022 走看看