您好,登錄后才能下訂單哦!
本篇內容主要講解“Tomcat的啟動過程是怎樣的”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“Tomcat的啟動過程是怎樣的”吧!
1.Tomcat分析
阿粉知道作為一個 Java 資深開發人員,對 Tomcat 那是再熟悉不過了,bin目錄、conf目錄、webapps目錄,對這些目錄熟悉的簡直不能再熟悉了。一言不合就是一個shutdown.sh,或者來個shutdown.bat,但是你知道你的啟動startup.bat,和startup.sh他們的啟動過程是什么過程么?接下來我們就開始進入分析吧。
2.Tomcat的整體結構圖
這個整體結構圖可不是大家想的目錄結構圖,目錄結構圖阿粉就不給大家展示了,自己去打開你的 Tomcat,里面就有你想看到目錄結構圖,那么整體結構圖是什么樣子的呢?
給大家解釋一下這個圖的意思,
Server:整個服務器。
Service:具體的服務。
Connector:提供Socket和request,response的連接。
Container:用于封裝和管理Servlet,以及具體的處理請求。
這個圖就把里面的包含關系說的是明明白白了,為什么這么說呢?因為一個Server中可以存在多個服務,也就是多個Service,而一個Service中可以存在多個Connector,但是只能存在一個Container,是不是就非常的清晰了呢?
3.Tomcat的啟動過程
接下來我們就來看看源碼里面的啟動過程吧,Bootstrap類中的啟動過程。
這個類的位置是在tomcat的catalina的包里面,大家看一下主方法也就是所謂的main方法,
public static void main(String[] args) { //對象初始化 if (daemon == null) { Bootstrap bootstrap = new Bootstrap(); try { bootstrap.init(); } catch (Throwable var3) { handleThrowable(var3); var3.printStackTrace(); return; } daemon = bootstrap; } else { Thread.currentThread().setContextClassLoader(daemon.catalinaLoader); } try { String command = "start"; if (args.length > 0) { command = args[args.length - 1]; } if (command.equals("startd")) { args[args.length - 1] = "start"; //加載 daemon.load(args); //啟動 daemon.start(); } else if (command.equals("stopd")) { args[args.length - 1] = "stop"; //停止 daemon.stop(); } else if (command.equals("start")) { daemon.setAwait(true); //加載并且啟動 daemon.load(args); daemon.start(); if (null == daemon.getServer()) { System.exit(1); } } else if (command.equals("stop")) { daemon.stopServer(args); } else if (command.equals("configtest")) { daemon.load(args); if (null == daemon.getServer()) { System.exit(1); } System.exit(0); } else { log.warn("Bootstrap: command \"" + command + "\" does not exist."); } } catch (Throwable var4) { Throwable t = var4; if (var4 instanceof InvocationTargetException && var4.getCause() != null) { t = var4.getCause(); } handleThrowable(t); t.printStackTrace(); System.exit(1); } }
main方法里面的存在也很簡單,先進行init的操作,然后再執行start,也就是說,啟動過程中,首先要進行初始化,然后接下來再進行啟動,最后階段在來個stop,這樣才算完整嘛。
load方法:其實說白了load方法就是根據server.xml文件創建Server并且調用Server的init方法進行初始化。
start方法:start方法很直白,啟動服務器。
stop方法:stop方法同樣,停止服務器。
在這里的start方法和stop方法調用的分別就是調用了Server內部的start和stop方法,而這三個方法都是按照圖中的層級結構來的,先從Server的load,start,stop,然后Server的start再調用Service的start,而Service的start調用的就是Connector和Container的start方法了,這從外到內的啟動,就可以把Tomcat完整的啟動起來了。
我們在接下來就繼續從外到內的啟動開始分析一波。
3.1 Catalina啟動過程
上面的啟動入口我們已經成功找到了,那么我們就繼續來,對象初始化完成后,執行了init的方法
Bootstrap bootstrap = new Bootstrap(); try { bootstrap.init(); } catch (Throwable var3) {
就是上面的這個,如果參數為空了,那么就開始調用start了,那么start方法是什么呢?
public void start() throws Exception { if (this.catalinaDaemon == null) { this.init(); } Method method = this.catalinaDaemon.getClass().getMethod("start", (Class[])null); method.invoke(this.catalinaDaemon, (Object[])null); }
上面的start方法就是直接使用invoke的方法映射到了catalinaDaemon,也就是到了Catalina的start的方法上,
而這個Catalina的啟動無非也就是調用了同樣的方法,setAwait方法,load方法,start方法,
setAwait方法:用于設置Server啟動完成時,是否進入等待,如果是true,那就等待,如果不是false,那就不進入等待。
load方法:創建并且初始化Server,
start方法:同樣是啟動服務器
同樣的setAwait方法比較少,阿粉就不給大家看了,無非就是個判斷,而load方法一定得看,
if (!this.loaded) { this.loaded = true; long t1 = System.nanoTime(); try { inputSource.setByteStream((InputStream)inputStream); digester.push(this); digester.parse(inputSource); break label242; } catch (SAXParseException var28) { log.warn("Catalina.start using " + this.getConfigFile() + ": " + var28.getMessage()); return; } catch (Exception var29) { log.warn("Catalina.start using " + this.getConfigFile() + ": ", var29); } } finally { if (inputStream != null) { try { ((InputStream)inputStream).close(); } catch (IOException var23) { ; } } } return; } try { //此處同樣調用的Server的init方法, this.getServer().init(); } catch (LifecycleException var24) { if (Boolean.getBoolean("org.apache.catalina.startup.EXIT_ON_INIT_FAILURE")) { throw new Error(var24); } log.error("Catalina.start", var24); } long t2 = System.nanoTime(); if (log.isInfoEnabled()) { log.info("Initialization processed in " + (t2 - t1) / 1000000L + " ms"); } }
而從這里就開始進入下一步了,Server的啟動過程,因為從Catalina里面已經找到了getServer的初始化方法,接下來就是要進行Server的初始化,然后加載,然后啟動的過程了。
3.2 Server的啟動過程
Server是Tomcat里面的接口,而不是類,那么我們就只能去找實現它的子類來于是就找到了StandardServer extends LifecycleMBeanBase implements Server。
阿粉一看有繼承,還有實現,那就先看看LifecycleMBeanBase這個被繼承的類,于是再次去看了它,
public abstract class LifecycleMBeanBase extends LifecycleBase implements JmxEnabled {
嗯?還有繼承?繼續往下扒拉,
public abstract class LifecycleBase implements Lifecycle {
終于算是找到了,
阿粉一看這init方法和start方法又調用了initInternal()和startInternal(),找來找去又回去了,而阿粉也從這里知道了,模板方法,是有自己的子類具體實現
于是回到了StandardServer自己的init和start方法,
protected void startInternal() throws LifecycleException { this.fireLifecycleEvent("configure_start", (Object)null); this.setState(LifecycleState.STARTING); this.globalNamingResources.start(); Object var1 = this.servicesLock; synchronized(this.servicesLock) { for(int i = 0; i < this.services.length; ++i) { this.services[i].start(); } } }
總得來說就是,StandardServer繼承自LifecycleMBeanBase,而LifecycleMBeanBase繼承自LifecycleBase,而LifecycleBase類中的模板方法,又讓自己的子類去進行具體的實現,但是我們要知道他的Tomcat生命周期中存在這些內容才行。
圖中都說了,Server里面有Service,那么一定就有,我們得去找找看,于是阿粉再次去找并且去看它到底是個什么意思,
public void addService(Service service) { service.setServer(this); Object var2 = this.servicesLock; synchronized(this.servicesLock) { Service[] results = new Service[this.services.length + 1]; System.arraycopy(this.services, 0, results, 0, this.services.length); results[this.services.length] = service; this.services = results; if (this.getState().isAvailable()) { try { service.start(); } catch (LifecycleException var6) { ; } } this.support.firePropertyChange("service", (Object)null, service); } }
位置是在Server的接口中出現了增加和刪除Service的方法,Server的init方法和start方法循環去調用每個Service的init方法和start方法。
接下來我們看看Service的具體實現,找到StandardService:
protected void initInternal() throws LifecycleException { super.initInternal(); if (this.engine != null) { this.engine.init(); } Executor[] arr$ = this.findExecutors(); int len$ = arr$.length; int len$; for(len$ = 0; len$ < len$; ++len$) { Executor executor = arr$[len$]; if (executor instanceof JmxEnabled) { ((JmxEnabled)executor).setDomain(this.getDomain()); } executor.init(); } this.mapperListener.init(); Object var11 = this.connectorsLock; synchronized(this.connectorsLock) { Connector[] arr$ = this.connectors; len$ = arr$.length; for(int i$ = 0; i$ < len$; ++i$) { Connector connector = arr$[i$]; try { connector.init(); } catch (Exception var9) { String message = sm.getString("standardService.connector.initFailed", new Object[]{connector}); log.error(message, var9); if (Boolean.getBoolean("org.apache.catalina.startup.EXIT_ON_INIT_FAILURE")) { throw new LifecycleException(message); } } } } }
而在方法中主要調用Executor,mapperListener,executor的init方法。
connector之前已經有了,而這個mapperListener就是Mapper的監聽器,用來堅挺container容器的變化。
到此,相信大家對“Tomcat的啟動過程是怎樣的”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。