首页 > 代码库 > tomcat系列分析之生命周期管理初始化动作

tomcat系列分析之生命周期管理初始化动作

tomcat中有很多组件,要对这些组件进行生命周期的管理非常困难,tomcat中采用的是抽象出一个生命周期管理接口,然后所有的组件都实现该接口,当父组件启动时,同事负责将子组件启动起来,从而完成整tomcat的初始、启动、结束等动作。

来看下tomcat启动的过程,首先构造Bootstrap类,调用其中的init方法,完成类加载器的初始化,方便后面加载类使用,然后调用其中的load方法,实际上tomcat真正的启动动作是由Catalina类完成的。而这其中在BootStrap中调用Catalina的load方法是通过反射完成的,按照how tomcat works的说法,这是为了解耦,可以方便的改变启动的方式。Catalina类继承了Embedded类,而Embedded又继承了StandardService类。而像StandardService或者ContainerBase(Container组件的基础父类)都实现了Lifecycle接口。从而可以方便的进行统一的处理。

StandardService中持有一个Server的引用,表示该Server下有一个Service服务,标准的Server实现是StandardServer:

// Start the new server
        //获取Server这里是一个标准的实现StandardService
        if (getServer() instanceof Lifecycle) {
            try {
			//返回StandardServer并调用初始化方法
                getServer().initialize();
            } 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);
                
            }
        }

可以看到先判断是否是Lifecycle的实现,如果是调用初始化方法,来看下该方法:

public void initialize()
        throws LifecycleException
    {
        if (initialized) {
                log.info(sm.getString("standardServer.initialize.initialized"));
            return;
        }
		//调用lifecycle的fireLifecycleEvent方法
        lifecycle.fireLifecycleEvent(INIT_EVENT, null);
        initialized = true;

		...........
		一个Server可以有多个Service,分别进行初始化
        // Initialize our defined Services
        for (int i = 0; i < services.length; i++) {
            services[i].initialize();
        }
    }

lifecycle是一个提供了对生命周期管理的类,其中持有Lifecycle实现类的引用。有必要看下这个fireLifecycleEvent方法,因为初始化动作全在这里面实现:

public void fireLifecycleEvent(String type, Object data) {
		//初始化话状态
        if (Lifecycle.INIT_EVENT.equals(type)) {
            state = "INITIALIZED";
        } else if (Lifecycle.BEFORE_START_EVENT.equals(type)) {
            state = "STARTING_PREP";
        } else if (Lifecycle.START_EVENT.equals(type)) {
            state = "STARTING";
        } else if (Lifecycle.AFTER_START_EVENT.equals(type)) {
            state = "STARTED";
        } else if (Lifecycle.BEFORE_STOP_EVENT.equals(type)) {
            state = "STOPPING_PREP";
        } else if (Lifecycle.STOP_EVENT.equals(type)) {
            state = "STOPPING";
        } else if (Lifecycle.AFTER_STOP_EVENT.equals(type)) {
            state = "STOPPED";
        } else if (Lifecycle.DESTROY_EVENT.equals(type)) {
            state = "DESTROYED";
        }
		//完成生命周期事件的生成
        LifecycleEvent event = new LifecycleEvent(lifecycle, type, data);
		获取该组件对应的生命周期监听器
        LifecycleListener interested[] = listeners;
        for (int i = 0; i < interested.length; i++)
		    //传递该事件,通过监听器完成组件的初始化动作
            interested[i].lifecycleEvent(event);

    }

这里应用到了监听器模式,收到不同的事件完成不同的动作。不同组件都持有一个LifecycleSupport的引用,当组件被new出来的时候,通过该引用完成相应事件的添加:

public StandardServer() {

        super();
        ServerFactory.setServer(this);

        globalNamingResources = new NamingResources();
        globalNamingResources.setContainer(this);

        if (isUseNaming()) {
            if (namingContextListener == null) {
                namingContextListener = new NamingContextListener();
                addLifecycleListener(namingContextListener);
            }
        }

    }

添加相应的listener,这样后面只要相应的调用LifecycleSupport的fireLifecycleEvent方法,构造出不同的事件,交由监听器出响应不同的动作。除了通过构造方法的初始化监听器外,还可能通过反射的机制调用addLifecycleListener完成监听器的添加。比如我们配置文件server.xml中的下面这几个监听器,全部由反射动态的注入的,因为我们无法得之用户会配哪些监听器。

<Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
  <!--Initialize Jasper prior to webapps are loaded. Documentation at /docs/jasper-howto.html -->
  <Listener className="org.apache.catalina.core.JasperListener" />
  <!-- Prevent memory leaks due to use of particular java/javax APIs-->
  <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
  <!-- JMX Support for the Tomcat server. Documentation at /docs/non-existent.html -->
  <Listener className="org.apache.catalina.mbeans.ServerLifecycleListener" />
  <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />

具体这些监听器都做了哪些初始化动作,就不看了,太多了。当完成自己的初始化动作后,调用子组件这里是service的初始化方法,我们知道一个service由一个container和多个connector组成,看了StandardService源码确实是这样的,来看下service的初始化动作:

public void initialize()
            throws LifecycleException
    {
        // Service shouldn't be used with embeded, so it doesn't matter
        if (initialized) {
            if(log.isInfoEnabled())
                log.info(sm.getString("standardService.initialize.initialized"));
            return;
        }
        initialized = true;

        if( oname==null ) {
            try {
                // Hack - Server should be deprecated...
				//获取service中的Container这里是engine(StandardEngine)
                Container engine=this.getContainer();
                domain=engine.getName();
                oname=new ObjectName(domain + ":type=Service,serviceName="+name);
                this.controller=oname;
                Registry.getRegistry(null, null)
                    .registerComponent(this, oname, null);
                
                Executor[] executors = findExecutors();
                for (int i = 0; i < executors.length; i++) {
                    ObjectName executorObjectName = 
                        new ObjectName(domain + ":type=Executor,name=" + executors[i].getName());
                    Registry.getRegistry(null, null)
                        .registerComponent(executors[i], executorObjectName, null);
                }
                
            } catch (Exception e) {
                log.error(sm.getString("standardService.register.failed",domain),e);
            }
            
            
        }
        if( server==null ) {
            // Register with the server 
            // HACK: ServerFactory should be removed...
            
            ServerFactory.getServer().addService(this);
        }
               

        // Initialize our defined Connectors
		//默认的connector是Connector[HTTP/1.1-8080], Connector[AJP/1.3-8009]这两种
        synchronized (connectors) {
            for (int i = 0; i < connectors.length; i++) {
                try {
				    //调用子组件的初始化动作
                    connectors[i].initialize();
                } catch (Exception e) {
                    String message = sm.getString(
                            "standardService.connector.initFailed",
                            connectors[i]);
                    log.error(message, e);

                    if (Boolean.getBoolean("org.apache.catalina.startup.EXIT_ON_INIT_FAILURE"))
                        throw new LifecycleException(message);
                }
            }
        }
    }

注意初始化的时候,Service并不涉及到生命周期组件的初始化动作,只是简单的由自己的方法做了必要的动作,然后直接触发Connector的初始化。

public void initialize()
        throws LifecycleException
    {
        this.initialized = true;

        ......

        // Initializa adapter
		//初始化connector的成员变量adapter和protocolHandler,这两个类后面会讲到
        adapter = new CoyoteAdapter(this);
        protocolHandler.setAdapter(adapter);

        // Make sure parseBodyMethodsSet has a default
        if( null == parseBodyMethodsSet )
            setParseBodyMethods(getParseBodyMethods());
		//反射调用,这个反射工具值得好好学习一下
        IntrospectionUtils.setProperty(protocolHandler, "jkHome",
                                       System.getProperty("catalina.base"));

        try {
		    //子组件的初始化,Http11Protocol和JkCoyoteHandler
            protocolHandler.init();
        } catch (Exception e) {
            throw new LifecycleException
                (sm.getString
                 ("coyoteConnector.protocolHandlerInitializationFailed", e));
        }
    }

重点看下Http11Protocol的init方法,Http11Protocol只是Connector内部的结构,并没有实现Lifecycle接口:

public void init() throws Exception {
        //endpoint类,该类为JIoEndpoin,是一个非常重要的类,有BIO和NIO的实现,后面会讲到
        endpoint.setName(getName());
		//cHandle同样是另外一个很重要的类Http11ConnectionHandler,该类为Http11Protocol的内部类
        endpoint.setHandler(cHandler);

        // Verify the validity of the configured socket factory
        try {
            if (isSSLEnabled()) {
                sslImplementation =
                    SSLImplementation.getInstance(sslImplementationName);
				//这里终于看到很熟悉的概念了,socket!不过是一个ServerSocket的工厂,很明显要去生产serverSocket
                socketFactory = sslImplementation.getServerSocketFactory();
				//咦?这里将这个工厂地址告诉了endpoint,可以大胆猜测下,ServerSocket的创建可能在endPoint中完成。
                endpoint.setServerSocketFactory(socketFactory);
            } else if (socketFactoryName != null) {
                socketFactory = (ServerSocketFactory) Class.forName(socketFactoryName).newInstance();
                endpoint.setServerSocketFactory(socketFactory);
            }
        } catch (Exception ex) {
            log.error(sm.getString("http11protocol.socketfactory.initerror"),
                      ex);
            throw ex;
        }
		//不过debug的时候,上面的socketFactory始终是null,不知道socketFactoryName是从哪里获取。
        if (socketFactory!=null) {
            Iterator<String> attE = attributes.keySet().iterator();
            while( attE.hasNext() ) {
                String key = attE.next();
                Object v=attributes.get(key);
                socketFactory.setAttribute(key, v);
            }
        }
		//endpoint的初始化动作
        try {
            endpoint.init();
        } catch (Exception ex) {
            log.error(sm.getString("http11protocol.endpoint.initerror"), ex);
            throw ex;
        }
        if (log.isInfoEnabled())
            log.info(sm.getString("http11protocol.init", getName()));

    }

一步步的跟,快要找到我们熟悉的socket了,先来看下JIoEndpoint类,该类实现了一个简单的server模型,一个监听线程负责接收客户端的socket,并为每个连接创建一个工作线程来处理socket,这里实际上并不是一连接一线程,而是有线程池来控制。看下JIoEndpoint类的初始化方法:

public void init()
        throws Exception {
        //这里的初始化动作,终于不那么晦涩了,很多熟悉的概念
        if (initialized)
            return;
        
        // Initialize thread count defaults for acceptor
		//初始化acceptor的个数,默认为1,acceptor负责接收客户端的连接。
        if (acceptorThreadCount == 0) {
            acceptorThreadCount = 1;
        }
		//这里我们并没有提供ServerSocketFactory,因此使用默认的工厂
        if (serverSocketFactory == null) {
            serverSocketFactory = ServerSocketFactory.getDefault();
        }
        if (serverSocket == null) {
            try {
			    //终于要初始化serverSocket了,port经典的8080,backlog是连接队列的最大等待个数服务端
				//某一时刻肯定只能处理一个客户端的连接,同一时刻其余连接全部放入等待队列中,如果满了,则拒绝连接
                if (address == null) {
                    serverSocket = serverSocketFactory.createSocket(port, backlog);
                } else {
                    serverSocket = serverSocketFactory.createSocket(port, backlog, address);
                }
            } catch (BindException orig) {
                String msg;
                if (address == null)
                    msg = orig.getMessage() + " <null>:" + port;
                else
                    msg = orig.getMessage() + " " +
                            address.toString() + ":" + port;
                BindException be = new BindException(msg);
                be.initCause(orig);
                throw be;
            }
        }
        //if( serverTimeout >= 0 )
        //    serverSocket.setSoTimeout( serverTimeout );
        
        initialized = true;
        
    }

终于到这里初始化动作完成。总结一下画出一张流程图:

技术分享

这里并没有涉及到service中的container初始化的动作,没错container并没有进行相应的初始化,但是很令人讨厌的一点是在engine或者context中确实有init方法,而这些方法是在start的时候调用的。start的过程下一节再去分析。




tomcat系列分析之生命周期管理初始化动作