日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

androidstudio在mainactivity实现监听器借口无法抽象_趣操作,Tomcat如何实现一键式启停?

發(fā)布時(shí)間:2025/3/15 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 androidstudio在mainactivity实现监听器借口无法抽象_趣操作,Tomcat如何实现一键式启停? 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

推薦閱讀

一線大廠為什么面試必問(wèn)分布式?

在一次又一次的失敗中,我總結(jié)了這份萬(wàn)字的《MySQL性能調(diào)優(yōu)筆記》

并發(fā)編程詳解:十三個(gè)工具類(lèi),十大設(shè)計(jì)模式,從理論基礎(chǔ)到案例實(shí)戰(zhàn)


首先我們通過(guò)一張簡(jiǎn)化的類(lèi)圖來(lái)回顧一下,從圖上你可以看到各種組件的層次關(guān)系,圖中的虛線表示一個(gè)請(qǐng)求在 Tomcat 中流轉(zhuǎn)的過(guò)程。

上面這張圖描述了組件之間的靜態(tài)關(guān)系,如果想讓一個(gè)系統(tǒng)能夠?qū)ν馓峁┓?wù),我們需要?jiǎng)?chuàng)建、組裝并啟動(dòng)這些組件;在服務(wù)停止的時(shí)候,我們還需要釋放資源,銷(xiāo)毀這些組件,因此這是一個(gè)動(dòng)態(tài)的過(guò)程。也就是說(shuō),Tomcat 需要?jiǎng)討B(tài)地管理這些組件的生命周期。

在我們實(shí)際的工作中,如果你需要設(shè)計(jì)一個(gè)比較大的系統(tǒng)或者框架時(shí),你同樣也需要考慮這幾個(gè)問(wèn)題:如何統(tǒng)一管理組件的創(chuàng)建、初始化、啟動(dòng)、停止和銷(xiāo)毀?如何做到代碼邏輯清晰?如何方便地添加或者刪除組件?如何做到組件啟動(dòng)和停止不遺漏、不重復(fù)?

今天我們就來(lái)解決上面的問(wèn)題,在這之前,先來(lái)看看組件之間的關(guān)系。如果你仔細(xì)分析過(guò)這些組件,可以發(fā)現(xiàn)它們具有兩層關(guān)系。

  • 第一層關(guān)系是組件有大有小,大組件管理小組件,比如 Server 管理 Service,Service 又管理連接器和容器。
  • 第二層關(guān)系是組件有外有內(nèi),外層組件控制內(nèi)層組件,比如連接器是外層組件,負(fù)責(zé)對(duì)外交流,外層組件調(diào)用內(nèi)層組件完成業(yè)務(wù)功能。也就是說(shuō),請(qǐng)求的處理過(guò)程是由外層組件來(lái)驅(qū)動(dòng)的。

這兩層關(guān)系決定了系統(tǒng)在創(chuàng)建組件時(shí)應(yīng)該遵循一定的順序。

  • 第一個(gè)原則是先創(chuàng)建子組件,再創(chuàng)建父組件,子組件需要被“注入”到父組件中。
  • 第二個(gè)原則是先創(chuàng)建內(nèi)層組件,再創(chuàng)建外層組件,內(nèi)層組建需要被“注入”到外層組件。

因此,最直觀的做法就是將圖上所有的組件按照先小后大、先內(nèi)后外的順序創(chuàng)建出來(lái),然后組裝在一起。不知道你注意到?jīng)]有,這個(gè)思路其實(shí)很有問(wèn)題!因?yàn)檫@樣不僅會(huì)造成代碼邏輯混亂和組件遺漏,而且也不利于后期的功能擴(kuò)展。

為了解決這個(gè)問(wèn)題,我們希望找到一種通用的、統(tǒng)一的方法來(lái)管理組件的生命周期,就像汽車(chē)“一鍵啟動(dòng)”那樣的效果。

一鍵式啟停:LifeCycle接口

我在前面說(shuō)到過(guò),設(shè)計(jì)就是要找到系統(tǒng)的變化點(diǎn)和不變點(diǎn)。這里的不變點(diǎn)就是每個(gè)組件都要經(jīng)歷創(chuàng)建、初始化、啟動(dòng)這幾個(gè)過(guò)程,這些狀態(tài)以及狀態(tài)的轉(zhuǎn)化是不變的。而變化點(diǎn)是每個(gè)具體組件的初始化方法,也就是啟動(dòng)方法是不一樣的。

因此,我們把不變點(diǎn)抽象出來(lái)成為一個(gè)接口,這個(gè)接口跟生命周期有關(guān),叫作 LifeCycle。LifeCycle 接口里應(yīng)該定義這么幾個(gè)方法:init()、start()、stop() 和 destroy(),每個(gè)具體的組件去實(shí)現(xiàn)這些方法。

理所當(dāng)然,在父組件的 init() 方法里需要?jiǎng)?chuàng)建子組件并調(diào)用子組件的 init() 方法。同樣,在父組件的 start() 方法里也需要調(diào)用子組件的 start() 方法,因此調(diào)用者可以無(wú)差別的調(diào)用各組件的 init() 方法和 start() 方法,這就是組合模式的使用,并且只要調(diào)用最頂層組件,也就是 Server 組件的 init() 和 start() 方法,整個(gè) Tomcat 就被啟動(dòng)起來(lái)了。下面是LifeCycle 接口的定義。

可擴(kuò)展性:LifeCycle事件

我們?cè)賮?lái)考慮另一個(gè)問(wèn)題,那就是系統(tǒng)的可擴(kuò)展性。因?yàn)楦鱾€(gè)組件 init() 和 start() 方法的具體實(shí)現(xiàn)是復(fù)雜多變的,比如在 Host 容器的啟動(dòng)方法里需要掃描 webapps 目錄下的Web 應(yīng)用,創(chuàng)建相應(yīng)的 Context 容器,如果將來(lái)需要增加新的邏輯,直接修改 start() 方法?這樣會(huì)違反開(kāi)閉原則,那如何解決這個(gè)問(wèn)題呢?開(kāi)閉原則說(shuō)的是為了擴(kuò)展系統(tǒng)的功能,你不能直接修改系統(tǒng)中已有的類(lèi),但是你可以定義新的類(lèi)。

我們注意到,組件的 init() 和 start() 調(diào)用是由它的父組件的狀態(tài)變化觸發(fā)的,上層組件的初始化會(huì)觸發(fā)子組件的初始化,上層組件的啟動(dòng)會(huì)觸發(fā)子組件的啟動(dòng),因此我們把組件的生命周期定義成一個(gè)個(gè)狀態(tài),把狀態(tài)的轉(zhuǎn)變看作是一個(gè)事件。而事件是有監(jiān)聽(tīng)器的,在監(jiān)聽(tīng)器里可以實(shí)現(xiàn)一些邏輯,并且監(jiān)聽(tīng)器也可以方便的添加和刪除,這就是典型的觀察者模式。

具體來(lái)說(shuō)就是在 LifeCycle 接口里加入兩個(gè)方法:添加監(jiān)聽(tīng)器和刪除監(jiān)聽(tīng)器。除此之外,我們還需要定義一個(gè) Enum 來(lái)表示組件有哪些狀態(tài),以及處在什么狀態(tài)會(huì)觸發(fā)什么樣的事件。因此 LifeCycle 接口和 LifeCycleState 就定義成了下面這樣。

從圖上你可以看到,組件的生命周期有 NEW、INITIALIZING、INITIALIZED、STARTING_PREP、STARTING、STARTED 等,而一旦組件到達(dá)相應(yīng)的狀態(tài)就觸發(fā)相應(yīng)的事件,比如 NEW 狀態(tài)表示組件剛剛被實(shí)例化;而當(dāng) init() 方法被調(diào)用時(shí),狀態(tài)就變成INITIALIZING 狀態(tài),這個(gè)時(shí)候,就會(huì)觸發(fā) BEFORE_INIT_EVENT 事件,如果有監(jiān)聽(tīng)器在監(jiān)聽(tīng)這個(gè)事件,它的方法就會(huì)被調(diào)用。

重用性:LifeCycleBase抽象基類(lèi)

有了接口,我們就要用類(lèi)去實(shí)現(xiàn)接口。一般來(lái)說(shuō)實(shí)現(xiàn)類(lèi)不止一個(gè),不同的類(lèi)在實(shí)現(xiàn)接口時(shí)往往會(huì)有一些相同的邏輯,如果讓各個(gè)子類(lèi)都去實(shí)現(xiàn)一遍,就會(huì)有重復(fù)代碼。那子類(lèi)如何重用這部分邏輯呢?其實(shí)就是定義一個(gè)基類(lèi)來(lái)實(shí)現(xiàn)共同的邏輯,然后讓各個(gè)子類(lèi)去繼承它,就達(dá)到了重用的目的。

而基類(lèi)中往往會(huì)定義一些抽象方法,所謂的抽象方法就是說(shuō)基類(lèi)不會(huì)去實(shí)現(xiàn)這些方法,而是調(diào)用這些方法來(lái)實(shí)現(xiàn)骨架邏輯。抽象方法是留給各個(gè)子類(lèi)去實(shí)現(xiàn)的,并且子類(lèi)必須實(shí)現(xiàn),否則無(wú)法實(shí)例化。

比如寶馬和榮威的底盤(pán)和骨架其實(shí)是一樣的,只是發(fā)動(dòng)機(jī)和內(nèi)飾等配套是不一樣的。底盤(pán)和骨架就是基類(lèi),寶馬和榮威就是子類(lèi)。僅僅有底盤(pán)和骨架還不是一輛真正意義上的車(chē),只能算是半成品,因此在底盤(pán)和骨架上會(huì)留出一些安裝接口,比如安裝發(fā)動(dòng)機(jī)的接口、安裝座椅的接口,這些就是抽象方法。寶馬或者榮威上安裝的發(fā)動(dòng)機(jī)和座椅是不一樣的,也就是具體子類(lèi)對(duì)抽象方法有不同的實(shí)現(xiàn)。

回到 LifeCycle 接口,Tomcat 定義一個(gè)基類(lèi) LifeCycleBase 來(lái)實(shí)現(xiàn) LifeCycle 接口,把一些公共的邏輯放到基類(lèi)中去,比如生命狀態(tài)的轉(zhuǎn)變與維護(hù)、生命事件的觸發(fā)以及監(jiān)聽(tīng)器的添加和刪除等,而子類(lèi)就負(fù)責(zé)實(shí)現(xiàn)自己的初始化、啟動(dòng)和停止等方法。為了避免跟基類(lèi)中的方法同名,我們把具體子類(lèi)的實(shí)現(xiàn)方法改個(gè)名字,在后面加上 Internal,叫 initInternal()、startInternal() 等。我們?cè)賮?lái)看引入了基類(lèi) LifeCycleBase 后的類(lèi)圖:

從圖上可以看到,LifeCycleBase 實(shí)現(xiàn)了 LifeCycle 接口中所有的方法,還定義了相應(yīng)的抽象方法交給具體子類(lèi)去實(shí)現(xiàn),這是典型的模板設(shè)計(jì)模式。

我們還是看一看代碼,可以幫你加深理解,下面是 LifeCycleBase 的 init() 方法實(shí)現(xiàn)。

@Overridepublic final synchronized void init() throws LifecycleException { //1.狀態(tài)檢查 if (!state.equals(LifecycleState.NEW)) { invalidTransition(Lifecycle.BEFORE_INIT_EVENT); } try { //2.觸發(fā)INITIALIZING事件的監(jiān)聽(tīng)器 setStateInternal(LifecycleState.INITIALIZING, null, false); //3.調(diào)用具體子類(lèi)的初始化方法 initInternal(); //4.觸發(fā)INITIALIZED事件的監(jiān)聽(tīng)器 setStateInternal(LifecycleState.INITIALIZED, null, false); } catch (Throwable t) { ... }}

這個(gè)方法邏輯比較清楚,主要完成了四步:

第一步,檢查狀態(tài)的合法性,比如當(dāng)前狀態(tài)必須是 NEW 然后才能進(jìn)行初始化。

第二步,觸發(fā) INITIALIZING 事件的監(jiān)聽(tīng)器:

在這個(gè) setStateInternal 方法里,會(huì)調(diào)用監(jiān)聽(tīng)器的業(yè)務(wù)方法。

第三步,調(diào)用具體子類(lèi)實(shí)現(xiàn)的抽象方法 initInternal() 方法。我在前面提到過(guò),為了實(shí)現(xiàn)一鍵式啟動(dòng),具體組件在實(shí)現(xiàn) initInternal() 方法時(shí),又會(huì)調(diào)用它的子組件的 init() 方法。

第四步,子組件初始化后,觸發(fā) INITIALIZED 事件的監(jiān)聽(tīng)器,相應(yīng)監(jiān)聽(tīng)器的業(yè)務(wù)方法就會(huì)被調(diào)用。

setStateInternal(LifecycleState.INITIALIZED, null, false);

總之,LifeCycleBase 調(diào)用了抽象方法來(lái)實(shí)現(xiàn)骨架邏輯。講到這里, 你可能好奇,LifeCycleBase 負(fù)責(zé)觸發(fā)事件,并調(diào)用監(jiān)聽(tīng)器的方法,那是什么時(shí)候、誰(shuí)把監(jiān)聽(tīng)器注冊(cè)進(jìn)來(lái)的呢?

分為兩種情況:

  • Tomcat 自定義了一些監(jiān)聽(tīng)器,這些監(jiān)聽(tīng)器是父組件在創(chuàng)建子組件的過(guò)程中注冊(cè)到子組件的。比如 MemoryLeakTrackingListener 監(jiān)聽(tīng)器,用來(lái)檢測(cè) Context 容器中的內(nèi)存泄漏,這個(gè)監(jiān)聽(tīng)器是 Host 容器在創(chuàng)建 Context 容器時(shí)注冊(cè)到 Context 中的。
  • 我們還可以在 server.xml 中定義自己的監(jiān)聽(tīng)器,Tomcat 在啟動(dòng)時(shí)會(huì)解析 server.xml,創(chuàng)建監(jiān)聽(tīng)器并注冊(cè)到容器組件。

生周期管理總體類(lèi)圖

通過(guò)上面的學(xué)習(xí),我相信你對(duì) Tomcat 組件的生命周期的管理有了深入的理解,我們?cè)賮?lái)看一張總體類(lèi)圖繼續(xù)加深印象。

這里請(qǐng)你注意,圖中的 StandardServer、StandardService 等是 Server 和 Service 組件的具體實(shí)現(xiàn)類(lèi),它們都繼承了 LifeCycleBase。

StandardEngine、StandardHost、StandardContext 和 StandardWrapper 是相應(yīng)容器組件的具體實(shí)現(xiàn)類(lèi),因?yàn)樗鼈兌际侨萜?#xff0c;所以繼承了 ContainerBase 抽象基類(lèi),而ContainerBase 實(shí)現(xiàn)了 Container 接口,也繼承了 LifeCycleBase 類(lèi),它們的生命周期管理接口和功能接口是分開(kāi)的,這也符合設(shè)計(jì)中接口分離的原則。

小結(jié)

Tomcat 為了實(shí)現(xiàn)一鍵式啟停以及優(yōu)雅的生命周期管理,并考慮到了可擴(kuò)展性和可重用性,將面向?qū)ο笏枷牒驮O(shè)計(jì)模式發(fā)揮到了極致,分別運(yùn)用了組合模式、觀察者模式、骨架抽象類(lèi)和模板方法。

如果你需要維護(hù)一堆具有父子關(guān)系的實(shí)體,可以考慮使用組合模式。觀察者模式聽(tīng)起來(lái)“高大上”,其實(shí)就是當(dāng)一個(gè)事件發(fā)生后,需要執(zhí)行一連串更新操作。傳統(tǒng)的實(shí)現(xiàn)方式是在事件響應(yīng)代碼里直接加更新邏輯,當(dāng)更新邏輯加多了之后,代碼會(huì)變得臃

腫,并且這種方式是緊耦合的、侵入式的。而觀察者模式實(shí)現(xiàn)了低耦合、非侵入式的通知與更新機(jī)制。

而模板方法在抽象基類(lèi)中經(jīng)常用到,用來(lái)實(shí)現(xiàn)通用邏輯。

新人創(chuàng)作打卡挑戰(zhàn)賽發(fā)博客就能抽獎(jiǎng)!定制產(chǎn)品紅包拿不停!

總結(jié)

以上是生活随笔為你收集整理的androidstudio在mainactivity实现监听器借口无法抽象_趣操作,Tomcat如何实现一键式启停?的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。