Tomcat系列2-初始化阶段源码分析

从Tomcat的启动脚本中可以看出Tomcat的入口是Bootstrap类的main方法。
Tomcat启动分为初始化init和启动start两个阶段。我们先分析初始化init阶段。

1.Bootstrap类

(1)main方法

   public static void main(String args[]) {
    	
        if (daemon == null) {
            // Don't set daemon until init() has completed
            Bootstrap bootstrap = new Bootstrap();
            try {
            //创建了catalina对象
                bootstrap.init();
            } catch (Throwable t) {
                handleThrowable(t);
                t.printStackTrace();
                return;
            }
            daemon = bootstrap;
        } else {
            // When running as a service the call to stop will be on a new
            // thread so make sure the correct class loader is used to prevent
            // a range of class not found exceptions.
            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")) {
                //执行这里的方法
                //调用catalina对象await方法
                daemon.setAwait(true);
                //调用catalina对象load方法
                daemon.load(args);
				//调用catalina对象start方法
                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.");
            }
        } 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);
        }

    }

Bootstrap类初始化:

  • bootstrap.init:创建Catalina对象
  • daemon.setAwait:调用catalina对象await方法
  • daemon.load:调用catalina对象load方法

(2)init方法

public void init() throws Exception {
        log.info("Bootstrap--------init()");
        //初始化class加载器
        //tomcat有三个class类加载器:commonLoader、catalinaLoader、sharedLoader
		//在这里catalinaLoader、sharedLoader指向的是commonLoader引用,三个对象其实相同的
		//在tomcat6之前的版本三个还是不同
        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");
		//实例化Catalina对象
        Object startupInstance = startupClass.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;
        Method method =
            startupInstance.getClass().getMethod(methodName, paramTypes);
        method.invoke(startupInstance, paramValues);

        catalinaDaemon = startupInstance;

    }

(3)setAwait方法

    public void setAwait(boolean await)
        throws Exception {

        Class<?> paramTypes[] = new Class[1];
        paramTypes[0] = Boolean.TYPE;
        Object paramValues[] = new Object[1];
        paramValues[0] = Boolean.valueOf(await);
        Method method =
            catalinaDaemon.getClass().getMethod("setAwait", paramTypes);
             //调用catalina对象await方法
		//设置catalina对象的await属性为true	
        method.invoke(catalinaDaemon, paramValues);

    }

(4)load方法

  private void load(String[] arguments)
        throws Exception {
        log.info("Bootstrap--------load()");
        // 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);

    }

2.Catalina类

(1)setAwait

 public void setAwait(boolean b) {
        await = b;
    }

就是将catalina对象的await属性设置为true,用来在容器启动后,由于main函数结束导致进程直接结束。
(2)load


    public void load() {
        log.info("Catalina--------load()");
        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 {
                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文件,创建Server、service、Engine、Connector等对象
                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();

        try {
		//调用StandardServer的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");
        }
    }

Catalina类在tomcat初始化时:

  • createStartDigester:创建Digester对象,用来解析xml文件
  • digester.parse:解析server.xml文件,创建Server、service、Engine、Connector等对象
  • getServer().init:开始初始化上述创建的对象。当然初始化是有顺序的,先创建父元素再创建子元素

3.StandardServer类init方法

Tomcat的server默认实现是StandardServer。StandardServer继承了LifecycleBase。LifecycleBase类实现了Lifecycle接口。Lifecycle接口是用来管理生命周期。Tomcat的server、service、engine都实现了Lifecycle接口。方便统一管理生命周期。
StandardServer的init方法实际上是LifecycleBase的方法。
(1)init

public final synchronized void init() throws LifecycleException {
        if (!state.equals(LifecycleState.NEW)) {
            invalidTransition(Lifecycle.BEFORE_INIT_EVENT);
        }

        try {
			//设置对象状态为before_init
            setStateInternal(LifecycleState.INITIALIZING, null, false);
			//调用子类实现的方法
            initInternal();
			//设置对象状态为after_init
            setStateInternal(LifecycleState.INITIALIZED, null, false);
        } catch (Throwable t) {
            ExceptionUtils.handleThrowable(t);
            setStateInternal(LifecycleState.FAILED, null, false);
            throw new LifecycleException(
                    sm.getString("lifecycleBase.initFail",toString()), t);
        }
    }

(2)initInternal方法

protected void initInternal() throws LifecycleException {
        log.info("StandardServer--------init()");
        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
		//调用NamingResourcesImpl的init方法
        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 e) {
                                // Ignore
                            } catch (IOException e) {
                                // Ignore
                            }
                        }
                    }
                }
                cl = cl.getParent();
            }
        }
		//调用StandardService的init方法
        for (int i = 0; i < services.length; i++) {
            services[i].init();
        }
    }

Server的初始化:

  • setStateInternal:设置Server的状态为before_init
  • initInternal:向MBeanFactory注册,调用service的初始化方法
  • setStateInternal:设置Server的状态为after_init

4.StandardService类init方法

Tomcat的service默认实现是StandardService。同样这里的init方法,也是LifecycleBase的init方法。StandardService初始化本质上还是调用自身的initInternal方法。
(1)initInternal


     protected void initInternal() throws LifecycleException {
        log.info("StandardService--------init()");
        super.initInternal();

        if (container != null) {
		//调用StandardEngine的init方法
            container.init();
        }

        for (Executor executor : findExecutors()) {
            if (executor instanceof JmxEnabled) {
                ((JmxEnabled) executor).setDomain(getDomain());
            }
			//执行线程池的init方法,将executor注册给JMX服务器
            executor.init();
        }

        // Initialize mapper listener
        mapperListener.init();

        synchronized (connectorsLock) {
            for (Connector connector : connectors) {
                try {
				//调用Connector的init方法
                    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);
                }
            }
        }
    }

Service的初始化:

  • setStateInternal:设置Service的状态为before_init
  • initInternal:顺序调用Engine的init方法,线程池executor的init方法,Connector的init方法
  • setStateInternal:设置Server的状态为after_init

5.Engine类init方法

Tomcat的Engine默认实现是StandardEngine。同理,init方法又会调用Engine的initInternal方法。
(1)initInternal方法

 protected void initInternal() throws LifecycleException {
        getRealm();
        super.initInternal();
    }
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();
    }

Engine的初始化:

  • setStateInternal:设置Engine的状态为before_init
  • initInternal:创建线程池
  • setStateInternal:设置Engine的状态为after_init

6.Connector类init方法

同样,init方法会执行initInternal方法,不过这个initInternal方法是Connector本身的方法。
(1)initInternal

protected void initInternal() throws LifecycleException {

        super.initInternal();

        //创建CoyoteAdapter
        adapter = new CoyoteAdapter(this);
		//创建ProtocolHandler,bio是Http11Protocol,nio是Http11NioProtocol
        protocolHandler.setAdapter(adapter);

        // 默认值
        if( null == parseBodyMethodsSet ) {
            setParseBodyMethods(getParseBodyMethods());
        }

        if (protocolHandler.isAprRequired() &&
                !AprLifecycleListener.isAprAvailable()) {
            throw new LifecycleException(
                    sm.getString("coyoteConnector.protocolHandlerNoApr",
                            getProtocolHandlerClassName()));
        }

        try {
        //调用protocolHandler的init方法
            protocolHandler.init();
        } catch (Exception e) {
            throw new LifecycleException
                (sm.getString
                 ("coyoteConnector.protocolHandlerInitializationFailed"), e);
        }
    }

Connector的初始化:

  • setStateInternal:设置Connector的状态为before_init
  • initInternal:创建CoyoteAdapter和ProtocolHandler,调用protocolHandler的init方法
  • setStateInternal:设置Connector的状态为after_init

(2)Connector内部重要属性说明
Connector内部有两个重要属性:ProtocolHandler和Adapter。
ProtocolHandler
ProtocolHandler是协议的处理类,不同的协议有不同的处理逻辑,Connector根据配置的不同实例化不同的ProtocolHandler。

public void setProtocol(String protocol) {

        if (AprLifecycleListener.isAprAvailable()) {
            if ("HTTP/1.1".equals(protocol)) {
                setProtocolHandlerClassName
                    ("org.apache.coyote.http11.Http11AprProtocol");
            } else if ("AJP/1.3".equals(protocol)) {
                setProtocolHandlerClassName
                    ("org.apache.coyote.ajp.AjpAprProtocol");
            } else if (protocol != null) {
                setProtocolHandlerClassName(protocol);
            } else {
                setProtocolHandlerClassName
                    ("org.apache.coyote.http11.Http11AprProtocol");
            }
        } else {
            if ("HTTP/1.1".equals(protocol)) {
                setProtocolHandlerClassName
                    ("org.apache.coyote.http11.Http11NioProtocol");
            } else if ("AJP/1.3".equals(protocol)) {
                setProtocolHandlerClassName
                    ("org.apache.coyote.ajp.AjpNioProtocol");
            } else if (protocol != null) {
                setProtocolHandlerClassName(protocol);
            }
        }

    }

Adapter
Adapter的实现时CoyoteAdapter,完成request的封装。

7.ProtocolHandler类init方法

ProtocolHandler是一个协议处理的接口。不同的协议有不同的实现,BIO为Http11Protocol,NiO为Http11NioProtocol。
Http11Protocol包含了Http11ConnectionHandler和JIoEndpoint两个对象。
Http11ConnectionHandler:
维护了Http11Processor对象池,调用CoyoteAdapter完成request的封装。
JIoEndpoint
维护Acceptor和Worker两个线程池。
Http11NioProtocol包含了Http11ConnectionHandler和NioEndpoint两个对象。
以NIO为例,说明下Acceptor和Poller、worker作用。
Acceptor
在NIO中,Acceptor是接收socket线程,获得SocketChannel对象并封装成NioChannel。然后再将NioChannel封装成PollerEvent对象并放入events queue里。
Poller
Poller线程中维护了一个Selector对象(主Selector),在connector中并不止一个Selector,在socket的读写数据时,为了控制timeout也有一个Selector。
Poller是NIO实现的主要线程。首先从events queue中取出PollerEvent对象,然后将对象中的channel以OP_READ事件注册到主Selector中,然后主Selector执行select操作,遍历出可以读数据的socket,并从Worker线程池中拿到可用的Worker线程去执行。
Worker
Worker线程拿到Poller传过来的socket后,将socket封装在SocketProcessor对象中。然后从Http11NioProcessor对象中调用CoyoteAdapter将从socket中读取的httprequest封装成HttpServletRequest对象,并分派到相应的servlet处理,最后将response通过socket发回client。
这里我们以Http11NioProtocol为例说明ProtocolHandler的初始化。Http11NioProtocol的init方法调用的是其父类AbstractHttp11JsseProtocol的init方法。

   public void init() throws Exception {
        // SSL implementation needs to be in place before end point is
        // initialized
        sslImplementation = SSLImplementation.getInstance(sslImplementationName);
        super.init();
    }

super.init()调用的是其父类AbstractProtocol的init方法。

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) {
            try {
                tpOname = new ObjectName(domain + ":" +
                        "type=ThreadPool,name=" + getName());
                Registry.getRegistry(null, null).registerComponent(endpoint,
                        tpOname, null);
            } catch (Exception e) {
                getLog().error(sm.getString(
                        "abstractProtocolHandler.mbeanRegistrationFailed",
                        tpOname, getName()), e);
            }
            rgOname=new ObjectName(domain +
                    ":type=GlobalRequestProcessor,name=" + getName());
            Registry.getRegistry(null, null).registerComponent(
                    getHandler().getGlobal(), rgOname, null );
        }

        String endpointName = getName();
        endpoint.setName(endpointName.substring(1, endpointName.length()-1));

        try {
		//调用NioEndpoint的init方法
            endpoint.init();
        } catch (Exception ex) {
            getLog().error(sm.getString("abstractProtocolHandler.initError",
                    getName()), ex);
            throw ex;
        }
    }

8.NioEndpoint类init方法

   public final void init() throws Exception {
        testServerCipherSuitesOrderSupport();
        if (bindOnInit) {
            bind();
            bindState = BindState.BOUND_ON_INIT;
        }
    }
 public void bind() throws Exception {

        serverSock = ServerSocketChannel.open();
        socketProperties.setProperties(serverSock.socket());
        InetSocketAddress addr = (getAddress()!=null?new InetSocketAddress(getAddress(),getPort()):new InetSocketAddress(getPort()));
		//绑定接口监听
        serverSock.socket().bind(addr,getBacklog());
        serverSock.configureBlocking(true); //mimic APR behavior
        serverSock.socket().setSoTimeout(getSocketProperties().getSoTimeout());

        // 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;
        }
		//限制最大连接数
        stopLatch = new CountDownLatch(pollerThreadCount);

        // Initialize SSL if needed
        if (isSSLEnabled()) {
            SSLUtil sslUtil = handler.getSslImplementation().getSSLUtil(this);

            sslContext = sslUtil.createSSLContext();
            sslContext.init(wrap(sslUtil.getKeyManagers()),
                    sslUtil.getTrustManagers(), null);

            SSLSessionContext sessionContext =
                sslContext.getServerSessionContext();
            if (sessionContext != null) {
                sslUtil.configureSessionContext(sessionContext);
            }
            // Determine which cipher suites and protocols to enable
            enabledCiphers = sslUtil.getEnableableCiphers(sslContext);
            enabledProtocols = sslUtil.getEnableableProtocols(sslContext);
        }

        if (oomParachute>0) reclaimParachute(true);
		//调用NioSelectorPool的open方法
        selectorPool.open();
    }

9.NioSelectorPool类open方法

(1)open方法

 public void open() throws IOException {
        enabled = true;
        getSharedSelector();
        if (SHARED) {
            blockingSelector = new NioBlockingSelector();
            blockingSelector.open(getSharedSelector());
        }

    }

这里的blockingSelector的open方法是NioBlockingSelector的open方法。

  public void open(Selector selector) {
        sharedSelector = selector;
        poller = new BlockPoller();
        poller.selector = sharedSelector;
        poller.setDaemon(true);
        poller.setName("NioBlockingSelector.BlockPoller-"+(++threadCounter));
        poller.start();
    }

这里的poller是个线程,看下它的run方法。
(2)run方法

  public void run() {
            while (run) {
                try {
				//将pollerEvent中的每个socketChannel注册到selector中
                    events();
                    int keyCount = 0;
                    try {
                        int i = wakeupCounter.get();
                        if (i>0)
						  //非阻塞的 select
                            keyCount = selector.selectNow();
                        else {
						 //阻塞selector,直到有准备就绪的socket
                            wakeupCounter.set(-1);
                            keyCount = selector.select(1000);
                        }
                        wakeupCounter.set(0);
                        if (!run) break;
                    }catch ( NullPointerException x ) {
                        //sun bug 5076772 on windows JDK 1.5
                        if (selector==null) throw x;
                        if ( log.isDebugEnabled() ) log.debug("Possibly encountered sun bug 5076772 on windows JDK 1.5",x);
                        continue;
                    } catch ( CancelledKeyException x ) {
                        //sun bug 5076772 on windows JDK 1.5
                        if ( log.isDebugEnabled() ) log.debug("Possibly encountered sun bug 5076772 on windows JDK 1.5",x);
                        continue;
                    } catch (Throwable x) {
                        ExceptionUtils.handleThrowable(x);
                        log.error("",x);
                        continue;
                    }

                    Iterator<SelectionKey> iterator = keyCount > 0 ? selector.selectedKeys().iterator() : null;

                    // Walk through the collection of ready keys and dispatch
                    // any active event.
					// 遍历就绪的socket
                    while (run && iterator != null && iterator.hasNext()) {
                        SelectionKey sk = iterator.next();
                        KeyAttachment attachment = (KeyAttachment)sk.attachment();
                        try {
                            attachment.access();
                            iterator.remove();
                            sk.interestOps(sk.interestOps() & (~sk.readyOps()));
							 // 可读或可写时减少对应闭锁的值,此时阻塞在 NioBlockingSelector.read() 上的线程继续执行读取
                            if ( sk.isReadable() ) {
                                countDown(attachment.getReadLatch());
                            }
                            if (sk.isWritable()) {
                                countDown(attachment.getWriteLatch());
                            }
                        }catch (CancelledKeyException ckx) {
                            sk.cancel();
                            countDown(attachment.getReadLatch());
                            countDown(attachment.getWriteLatch());
                        }
                    }//while
                }catch ( Throwable t ) {
                    log.error("",t);
                }
            }
            events.clear();
            // If using a shared selector, the NioSelectorPool will also try and
            // close the selector. Try and avoid the ClosedSelectorException
            // although because multiple threads are involved there is always
            // the possibility of an Exception here.
            if (selector.isOpen()) {
                try {
                    // Cancels all remaining keys
                    selector.selectNow();
                }catch( Exception ignore ) {
                    if (log.isDebugEnabled())log.debug("",ignore);
                }
            }
            try {
                selector.close();
            }catch( Exception ignore ) {
                if (log.isDebugEnabled())log.debug("",ignore);
            }
        }

(3)events方法

      public boolean events() {
            boolean result = false;
            Runnable r = null;
            result = (events.size() > 0);
			//将pollerEvent中的每个socketChannel注册到selector中
            while ( (r = events.poll()) != null ) {
                r.run();
                result = true;
            }
            return result;
        }

到这里整个初始化过程就基本结束了。但是不是有点疑惑,怎么没看到Host、Context、Valve的初始化,这个在后面start部分会分析到。

10.总结

tomcat初始化过程:

  • 创建Catalina对象,调用其load方法创建Digester解析server.xml,调用Server的初始化方法
  • Server循环调用内部Service的初始化方法
  • Service顺序调用内部的Engine、Connector初始化方法
  • Connector初始化会根据协议创建ProtocolHandler和CoyoteAdapter,然后调用ProtocolHandler的初始化方法
  • ProtocolHandler的初始化会调用Endpoint的初始化方法
  • Endpoint初始化方法会根据协议的不同调用不同Endpoint的bind方法。BIO调用的是JIoEndpoint的bind方法,设置最大连接,创建ServerSocket监听连接。NIO调用的是NioEndpoint的bind方法,创建ServerSocket监听连接,调用NioSelectorPool的open方法获得NioBlockingSelect,然后调用
    它的open方法。
  • NioBlockingSelect的open方法开启poller线程,从event队列中获取连接,注册到Selector上等待读写请求。
    最后看一张各组件结构图。
    在这里插入图片描述
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值