作為java程序員,對于tomcat的server.xml想必都不陌生。本文基于Tomcat7.0的Java源碼,對server.xml文件是如何加載的進行分析。
Bootstrap的load方法是加載tomcat的server.xml的入口,load方法實際通過反射調用了Catalina的load方法,見代碼清單1。
代碼清單1
/** * Load daemon. */PRivate void load(String[] arguments) throws Exception { // 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); method.invoke(catalinaDaemon, param);}
Catalina的load方法的實現見代碼清單2。
代碼清單2
/** * Start a new server instance. */public void load() { long t1 = System.nanoTime(); initDirs(); // Before digester - it may be needed initNaming(); // Create and execute our Digester Digester digester = createStartDigester(); 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) { // Ignore } if (inputStream == null) { try { inputStream = getClass().getClassLoader() .getResourceAsStream(getConfigFile()); inputSource = new InputSource (getClass().getClassLoader() .getResource(getConfigFile()).toString()); } catch (Exception e) { // Ignore } } // 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) { // Ignore } } 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 try { 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");}
這里對代明清單2進行分析,其執行步驟如下:
1) initDirs方法用于對catalina.home和catalina.base的一些檢查工作。
2) initNaming方法給系統設置java.naming.factory.url.pkgs和java.naming.factory.initial。在創建JNDI上下文時,使用Context.INITIAL_CONTEXT_FACTORY("java.naming.factory.initial")屬性,來指定創建JNDI上下文的工廠類;Context.URL_PKG_PREFIXES("java.naming.factory.url.pkgs")用在查詢url中包括scheme方法id時創建對應的JNDI上下文,例如查詢"java:/jdbc/test1"等類似查詢上,即以冒號":"標識的shceme。Context.URL_PKG_PREFIXES屬性值有多個java 包(package)路徑,其中以冒號":"分隔各個包路徑,這些包路徑中包括JNDI相關實現類。當在JNDI上下文中查找"java:"這類包括scheme方案ID的url時,InitialContext類將優先查找Context.URL_PKG_PREFIXES屬性指定的包路徑中是否存在 scheme+"."+scheme + "URLContextFactory"工廠類(需要實現ObjectFactory接口),如果存在此工廠類,則調用此工廠類的getObjectInstance方法獲得此scheme方案ID對應的jndi上下文,再在此上下文中繼續查找對應的url。
3) createStartDigester方法創建并配置將要用來啟動的Digester實例,并且設置一系列Rule,具體映射到server.xml。
4) 使用FileInputStream獲取conf/server.xml配置文件輸入流。
5) 將FileInputStream封裝為InputSource,并且調用Digester的parse方法進行解析。
6) initStreams對輸出流、錯誤流重定向。
7) 初始化server,具體實現本文不做分析。
從上面的分析可以看到,tomcat加載server.xml配置文件的方式,非常傳統,正是使用FileInputStream進行加載的。有關server.xml配置文件的解析會在之后補充。
新聞熱點
疑難解答