Tomcatのソースを読んでみる - Catalinaの初期化
前回、Digesterオブジェクトを作成するところまで書きました。
Apache Commons Digesterとは、XMLをJavaオブジェクトにマッピングするクラスです。
public class Catalina extends Embedded { //------------------------------------------------中略 protected Digester createStartDigester() { long t1=System.currentTimeMillis(); // Initialize the digester Digester digester = new Digester(); digester.setValidating(false); digester.setRulesValidation(true); HashMap<Class, List<String>> fakeAttributes = new HashMap<Class, List<String>>(); ArrayList<String> attrs = new ArrayList<String>(); attrs.add("className"); fakeAttributes.put(Object.class, attrs); digester.setFakeAttributes(fakeAttributes); digester.setClassLoader(StandardServer.class.getClassLoader()); // Configure the actions we will be using digester.addObjectCreate("Server", "org.apache.catalina.core.StandardServer", "className"); digester.addSetProperties("Server"); digester.addSetNext("Server", "setServer", "org.apache.catalina.Server"); digester.addObjectCreate("Server/GlobalNamingResources", "org.apache.catalina.deploy.NamingResources"); digester.addSetProperties("Server/GlobalNamingResources"); digester.addSetNext("Server/GlobalNamingResources", "setGlobalNamingResources", "org.apache.catalina.deploy.NamingResources"); //---------------------------------------中略 // Add RuleSets for nested elements digester.addRuleSet(new NamingRuleSet("Server/GlobalNamingResources/")); digester.addRuleSet(new EngineRuleSet("Server/Service/")); digester.addRuleSet(new HostRuleSet("Server/Service/Engine/")); digester.addRuleSet(new ContextRuleSet("Server/Service/Engine/Host/")); digester.addRuleSet(ClusterRuleSetFactory.getClusterRuleSet("Server/Service/Engine/Host/Cluster/")); digester.addRuleSet(new NamingRuleSet("Server/Service/Engine/Host/Context/")); // When the 'engine' is found, set the parentClassLoader. digester.addRule("Server/Service/Engine", new SetParentClassLoaderRule(parentClassLoader)); digester.addRuleSet(ClusterRuleSetFactory.getClusterRuleSet("Server/Service/Engine/Cluster/"));
server.xmlのDOM構造に合わせてXML解析ルールを設定しています。
InputSource inputSource = null; InputStream inputStream = null; File file = null; try { file = configFile(); inputStream = new FileInputStream(file); inputSource = new InputSource("file://" + file.getAbsolutePath()); } catch (Exception e) { ; } if (inputStream == null) { try { inputStream = getClass().getClassLoader() .getResourceAsStream(getConfigFile()); inputSource = new InputSource (getClass().getClassLoader() .getResource(getConfigFile()).toString()); } catch (Exception 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 ((inputStream == null) && (file != null)) { log.warn("Can't load server.xml from " + 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); digester.parse(inputSource); inputStream.close(); } catch (Exception e) { log.warn("Catalina.start using " + getConfigFile() + ": " , e); return; } // Stream redirection initStreams(); // Start the new server if (getServer() instanceof Lifecycle) { try { 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); } } long t2 = System.nanoTime(); if(log.isInfoEnabled()) log.info("Initialization processed in " + ((t2 - t1) / 1000000) + " ms"); }
Digesterオブジェクトに解析ルールを設定した後、
digester.push()でcatalinaオブジェクトをのせて、
digester.parse()で設定したルールに基づいてそれぞれオブジェクトにマッピングします。
次にgetServer().initialize()でStandardServer#initialize()を呼び出しています。
ここからの処理はデザインパターンの一つである
Template Methodパターンを使っています。
処理の大概を親クラスで実装し、異なる部分だけをそれぞれの子クラスで実装するようです。
ここからの処理は分かりにくいので、下記シーケンスを参考にします。
http://tomcat.apache.org/tomcat-7.0-doc/architecture/startup/serverStartup.pdf
public final class StandardServer implements Lifecycle, Server, MBeanRegistration { /** * Invoke a pre-startup initialization. This is used to allow connectors * to bind to restricted ports under Unix operating environments. */ public void initialize() throws LifecycleException { if (initialized) { log.info(sm.getString("standardServer.initialize.initialized")); return; } lifecycle.fireLifecycleEvent(INIT_EVENT, null); initialized = true; if( oname==null ) { try { oname=new ObjectName( "Catalina:type=Server"); Registry.getRegistry(null, null) .registerComponent(this, oname, null ); } catch (Exception e) { log.error("Error registering ",e); } } // Register global String cache try { ObjectName oname2 = new ObjectName(oname.getDomain() + ":type=StringCache"); Registry.getRegistry(null, null) .registerComponent(new StringCache(), oname2, null ); } catch (Exception e) { log.error("Error registering ",e); } // Initialize our defined Services for (int i = 0; i < services.length; i++) { services[i].initialize(); } }
アプリケーション管理技術のJMXでCatalinaのtype属性のserverのオブジェクト(StandardServer)を作成し、MBeansに登録しています。 StandardServer#initialize()の中でStandardService#initialize()を呼び出しています。
public class StandardService implements Lifecycle, Service, MBeanRegistration { /** * Invoke a pre-startup initialization. This is used to allow connectors * to bind to restricted ports under Unix operating environments. */ public void initialize() throws LifecycleException { //--------------------------------------------------------------中略 // Initialize our defined Connectors 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); } } } }
そして、StandardService#initialize()の中でConnector#initialize()を呼び出しています。
/** * Implementation of a Coyote connector. * * @author Craig R. McClanahan * @author Remy Maucherat * */ public class Connector implements Lifecycle, MBeanRegistration { public Connector(String protocol) throws Exception { setProtocol(protocol); // Instantiate protocol handler try { Class clazz = Class.forName(protocolHandlerClassName); this.protocolHandler = (ProtocolHandler) clazz.newInstance(); } catch (Exception e) { log.error (sm.getString ("coyoteConnector.protocolHandlerInstantiationFailed", e)); } } /** * Initialize this connector (create ServerSocket here!) */ public void initialize() throws LifecycleException { //------------------------------------------------中略 // Initializa adapter adapter = new CoyoteAdapter(this); protocolHandler.setAdapter(adapter); //------------------------------------------------中略 try { protocolHandler.init(); } catch (Exception e) { throw new LifecycleException (sm.getString ("coyoteConnector.protocolHandlerInitializationFailed", e)); } }
ConnectorでCoyoteAdapterを作成し、Connectorのコンストラクタで
生成されたprotocolHandlerにセットします。
その後、protocolHandler.init()で初期化します。
Connectorの中では、初期設定はHTTP/1.1コネクタが設定されます
org.apache.coyote.http11.Http11Protocol - HTTP/1.1コネクタorg.apache.coyote.http11.Http11NioProtocol - 非ブロックJavaコネクタorg.apache.coyote.http11.Http11AprProtocol - APR(Apache Portable Runtime)コネクタ
があります。
public interface ProtocolHandler { //------------------------------------------------中略 } public abstract class AbstractProtocol implements ProtocolHandler { //------------------------------------------------中略 } public class Http11Protocol extends AbstractProtocol implements MBeanRegistration { public void init() throws Exception { endpoint.setName(getName()); endpoint.setHandler(cHandler); //------------------------------------------------中略 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())); }
Http11Protocol#init()の中でJloEndpointを初期化します。
ようやくCatalina関連の初期化処理が終わりましたので、
次回はサーバの開始処理を見てみます。
Javaオープンソース徹底攻略―Eclipse,JBoss,Tomcat,Strutsから最新のXML/WebServicesまで
- 作者: 岡本隆史,吉田英嗣,山口卓也,樋山大輔
- 出版社/メーカー: ソフトリサーチセンター
- 発売日: 2003/12
- メディア: 単行本
- 購入: 1人 クリック: 78回
- この商品を含むブログ (10件) を見る