tomcat原始碼系列二(初始化啟動)
Tomcat 的結構很複雜,但是 Tomcat 也非常的模組化,找到了 Tomcat 最核心的模組,您就抓住了 Tomcat 的“七寸”。下面是 Tomcat 的總體結構圖:
從上圖中可以看出 Tomcat 的心臟是兩個元件:Connector 和 Container,關於這兩個元件將在後面詳細介紹。Connector 元件是可以被替換,這樣可以提供給伺服器設計者更多的選擇,因為這個元件是如此重要,不僅跟伺服器的設計的本身,而且和不同的應用場景也十分相關,所以一個 Container 可以選擇對應多個 Connector。多個 Connector 和一個 Container 就形成了一個 Service,Service 的概念大家都很熟悉了,有了 Service 就可以對外提供服務了,但是 Service 還要一個生存的環境,必須要有人能夠給她生命、掌握其生死大權,那就非 Server 莫屬了。所以整個 Tomcat 的生命週期由 Server 控制。
通過關鍵類來看Tomcat結構
Tomcat啟動
當通過 ./startup.sh
指令碼或直接通過 java
命令來啟動 Bootstrap
時,Tomcat 的啟動過程就正式開始了,啟動的入口點就是 Bootstrap
類的 main
方法。
啟動的過程分為三步,分別為:
1. Bootstrap初始化 Bootstrap bootstrap = new Bootstrap(); bootstrap.init(); daemon = bootstrap; 2. load和start daemon.load(args); daemon.start();
bootstrap.init()
先貼出原始碼,在原始碼中標註了順序,下面詳解
/** * Initialize daemon. */ public void init() throws Exception { //1. Set Catalina path setCatalinaHome(); setCatalinaBase(); //2. 初始化classLoader initClassLoaders(); Thread.currentThread().setContextClassLoader(catalinaLoader); SecurityClassLoad.securityClassLoad(catalinaLoader); // Load our startup class and call its process() method if (log.isDebugEnabled()) log.debug("Loading startup class"); Class<?> startupClass = catalinaLoader.loadClass ("org.apache.catalina.startup.Catalina"); Object startupInstance = startupClass.newInstance(); // Set the shared extensions class loader if (log.isDebugEnabled()) log.debug("Setting startup class properties"); String methodName = "setParentClassLoader"; Class<?> paramTypes[] = new Class[1]; paramTypes[0] = Class.forName("java.lang.ClassLoader"); Object paramValues[] = new Object[1]; paramValues[0] = sharedLoader; Method method = startupInstance.getClass().getMethod(methodName, paramTypes); //3. 設定parentClassLoader method.invoke(startupInstance, paramValues); // 4. 將catalinaDaemon賦值為Catalia例項 catalinaDaemon = startupInstance; }
- Set Catalina path (設定catalina的路徑資訊)
- initClassLoaders(初始化三個ClassLoader)
- 設定Catalina的parentClassLoader
- 將catalinaDaemon賦值為Catalia例項
daemon.load(args)
貼出原始碼:
/** * 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); }
可以看出這個做的主要事情是呼叫catalinaDaemon.load()
在第一步init的時候 知道catalinaDaemon為Catalina的例項,所以看下catalina.load(),其中的關鍵性程式碼如下:
//1. Create and execute our Digester Digester digester = createStartDigester(); InputSource inputSource = null; InputStream inputStream = null; File file = null; // 2.讀取配置檔案conf/server.xml file = configFile(); inputStream = new FileInputStream(file); inputSource = new InputSource(file.toURI().toURL().toString()); inputSource.setByteStream(inputStream); digester.push(this); // 3.解析配置檔案 digester.parse(inputSource); getServer().setCatalina(this); // Stream redirection initStreams(); // 4.初始化server主要初始化宣告週期 getServer().init();