tomcat源码分析之Observer方式以及应用加载-Lifecycle
研究过tomcat源码的朋友们可能都发现了,tomcat中几个主要的component都实现了Lifecycle接口,并且在
start的时候通常都会publish一些事件。在这个过程中tomcat是通过Observer模式来实现相关功能的。下面以StandardHost为例来说明。
StandardHost是StandardContext(也就是部署在tomcat下面的一个个应用)的上级Container.Host是在Digester server.xml文件的时候生成的。但是,在digester的时候,并没有standardcontext的相关配置。那么,StandardContext是如何加载的呢?
下面就来研究一下standardhost的源码:
先来看init源码:
public void init() { if( initialized ) return; initialized=true; // already registered. if( getParent() == null ) { try { // Register with the Engine ObjectName serviceName=new ObjectName(domain + ":type=Engine"); HostConfig deployer = new HostConfig(); addLifecycleListener(deployer); if( mserver.isRegistered( serviceName )) { if(log.isDebugEnabled()) log.debug("Registering "+ serviceName +" with the Engine"); mserver.invoke( serviceName, "addChild", new Object[] { this }, new String[] { "org.apache.catalina.Container" } ); } } catch( Exception ex ) { log.error("Host registering failed!",ex); } } if( oname==null ) { // not registered in JMX yet - standalone mode try { StandardEngine engine=(StandardEngine)parent; domain=engine.getName(); if(log.isDebugEnabled()) log.debug( "Register host " + getName() + " with domain "+ domain ); oname=new ObjectName(domain + ":type=Host,host=" + this.getName()); controller = oname; Registry.getRegistry(null, null) .registerComponent(this, oname, null); } catch( Throwable t ) { log.error("Host registering failed!", t ); } } }
StandardHost本身是一个container(ContainerBase),从以上代码可以看出,它在初始化的时候注册了一个LifecycleListener:HostConfig. 不同于一般的Observer模式的地方是,standard并不直接拥有listeners,而是通过拥有一个工具类-LifecycleSupport来维护与listeners的关系。这样就使得代码看起来很干净。已经注册了Observer,那么在哪里触发事件呢?事件触发是在container启动的时候(其实观察tomcat6中的重要组件,比如standardserver,standardservice以及container如standardengine,standardhost,standardcontext,他们在start的时候都会发布这么几个事件:beforestartevent,startevent,afterstartevent). 于是在standardhost start的时候,触发事件,listeners作出响应,hostconfig的响应代码如下:
public void lifecycleEvent(LifecycleEvent event) { if (event.getType().equals(Lifecycle.PERIODIC_EVENT)) check(); // Identify the host we are associated with try { host = (Host) event.getLifecycle(); if (host instanceof StandardHost) { setDeployXML(((StandardHost) host).isDeployXML()); setUnpackWARs(((StandardHost) host).isUnpackWARs()); setXmlNamespaceAware(((StandardHost) host).getXmlNamespaceAware()); setXmlValidation(((StandardHost) host).getXmlValidation()); } } catch (ClassCastException e) { log.error(sm.getString("hostConfig.cce", event.getLifecycle()), e); return; } // Process the event that has occurred if (event.getType().equals(Lifecycle.START_EVENT)) start(); else if (event.getType().equals(Lifecycle.STOP_EVENT)) stop(); }
可以看出,如果触发的事件是START_EVENT,那么hostconfig调用自己的start方法。而正是在
start方法里面,调用deployApps来生成standardContext.
至此,不仅了解了tomcat中Lifecycle的Observer模式,而且了解了tomcat加载应用的流程。可谓一举两得。