首页 > 代码库 > 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系列分析之生命周期管理初始化动作