squbs 帶有一個(gè)默認(rèn)的引導(dǎo)類 org.squbs.unicomplex.Bootstrap。可以從IDE、命令行、sbt、甚至Maven啟動(dòng)。引導(dǎo)程序掃描類加載器并在每個(gè)加載的 jar 包中查找META-INF/squbs-meta.<ext>。如果 squbs 元數(shù)據(jù)可用, 則 jar 包將被視為 squbs cube或擴(kuò)展, 并根據(jù)元數(shù)據(jù)聲明進(jìn)行初始化。然后, 引導(dǎo)程序首先初始化擴(kuò)展、cubes, 然后是服務(wù)處理程序, 而不管它們?cè)陬惵窂街械捻樞蛉绾巍?/p>
在正常情況下, 引導(dǎo)細(xì)節(jié)沒有多大意義。然而,可能需要以編程方式用不同的方案引導(dǎo) squbs。這在需要自定義配置且需要并行運(yùn)行的測(cè)試用例中尤其常見。有關(guān)詳細(xì)信息, 請(qǐng)參閱測(cè)試。引導(dǎo) squbs 的語法如下:
選項(xiàng)1)使用自定義配置啟動(dòng)
UnicomplexBoot(customConfig)
.createUsing {(name, config) => ActorSystem(name, config)}
.scanResources()
.initExtensions
.stopJVMOnExit
.start()
選項(xiàng)2)使用默認(rèn)配置啟動(dòng)
UnicomplexBoot {(name, config) => ActorSystem(name, config)}
.scanResources()
.initExtensions
.stopJVMOnExit
.start()
1.創(chuàng)建UnicomplexBoot (boot)對(duì)象。通過傳入一個(gè)自定義配置或者ActorSystem創(chuàng)建閉包給UnicomplexBoot.apply(),完成。
2.在上面的示例中顯示為 customConfig 的配置對(duì)象。它是一個(gè)從Typesafe Config 庫的解析函數(shù)獲取的配置對(duì)象。此配置對(duì)象尚未與reference.conf合并。它是可選的,替代其它 application.conf 配置中的定義。
3.傳入一個(gè)函數(shù)或閉包來創(chuàng)建ActorSystem。實(shí)際創(chuàng)建發(fā)生在啟動(dòng)階段(下面第7項(xiàng))。默認(rèn)的函數(shù)是{(name, config) => ActorSystem(name, config)}。傳入的名稱是從配置文件中讀取的ActorSystem名稱。這個(gè)config是所有配置合并后加載的配置對(duì)象。大多數(shù)用例都希望以這種方式創(chuàng)建 ActorSystem, 因此不需要提供函數(shù)。createUsing可以完全避免。
4.使用scanResources()函數(shù)掃描組件查找cubes、服務(wù)或者擴(kuò)展。這是強(qiáng)制性的, 否則將不啟動(dòng)任何組件。如果沒有傳遞參數(shù), squbs 引導(dǎo)程序?qū)呙杵漕惣虞d器。測(cè)試用例可能希望只針對(duì)某些組件進(jìn)行掃描。可以傳入另外的squbs-meta.conf文件位置(作為scanResources的一個(gè)變量參數(shù)),例如.scanResources("component1/META-INF/squbs-meta.conf", "component2/META-INF/squbs-meta.conf")。將掃描你的類路徑以及另外所給資源。如果你不想掃描類路徑,傳入withClassPath = false 或者在資源列表前的第一個(gè)參數(shù)僅傳入false:.scanResources(withClassPath = false, "component1/META-INF/squbs-meta.conf", "component2/META-INF/squbs-meta.conf")。
5.使用initExtension函數(shù)初始化擴(kuò)展。將初始化掃描到的所有擴(kuò)展。擴(kuò)展的初始化將在ActorSystem創(chuàng)建前完成。對(duì)于多個(gè)Unicomplex用例(即多個(gè)ActorSystem),同一擴(kuò)展不能多次初始化。一個(gè)擴(kuò)展只能由一個(gè)測(cè)試用例使用。在某些測(cè)試用例中, 我們根本不希望初始化擴(kuò)展, 也不會(huì)調(diào)用 initExtension。
6.在退出時(shí)停止 JVM。這是通過調(diào)用stopJVMOnExit函數(shù)來啟用的。通常不應(yīng)將此選項(xiàng)用于測(cè)試用例。它是由 squbs 的引導(dǎo)使用, 以確保 squbs 關(guān)閉和正確退出。
7.通過調(diào)用start()啟動(dòng)Unicomplex。這是一個(gè)強(qiáng)制性的步驟。沒有它,沒有ActorSystem啟動(dòng),沒有Actor運(yùn)行。在系統(tǒng)完全啟動(dòng)和運(yùn)行之前, start調(diào)用會(huì)阻塞或者產(chǎn)生一個(gè)超時(shí)。當(dāng)啟動(dòng)超時(shí)時(shí), 某些組件可能仍在初始化, 使系統(tǒng)處于Initializing狀態(tài)。然而,任何單個(gè)組件故障都將使系統(tǒng)在超時(shí)時(shí)狀態(tài)為Failed。這將允許系統(tǒng)組件 (如系統(tǒng)診斷程序) 運(yùn)行并完成。默認(rèn)的啟動(dòng)超時(shí)設(shè)置為60秒。對(duì)于預(yù)期超時(shí)的測(cè)試, 可以設(shè)置更小的值,通過向start()傳入要求的超時(shí),例如start(Timeout(5 seconds))或更短的start(5 seconds)(使用從duration到timeout的隱式轉(zhuǎn)換)。
配置解析
squbs 選擇一個(gè)應(yīng)用程序配置, 并將其與類路徑下的聚合的application.conf和reference.conf合并。正在合并的應(yīng)用程序配置從以下順序選擇:
1.如果創(chuàng)建boot對(duì)象時(shí)提供了一個(gè)配置,這個(gè)配置將被選中。即上例中的customConfig字段。
2.如果在外部配置目錄中提供了application.conf文件, 則此application.conf將被選中。外部配置目錄是通過設(shè)置squbs.external-config-dir來配置的,默認(rèn)是squbsconfig。不可以通過提供的配置或外部配置來更改或重寫此目錄(因?yàn)槟夸洷旧硎鞘褂门渲脤傩源_定的)。
3.否則,將使用與應(yīng)用程序一起提供的application.conf(如果有將使用)。然后,回到reference.conf。
模塊化系統(tǒng)
squbs將應(yīng)用劃分到稱為cube的模塊中。squbs中的模塊旨在以模塊化隔離以及類路徑上運(yùn)行。模塊隔離目的在真正的模塊間松耦合,不會(huì)由于依賴出現(xiàn)任何類路徑?jīng)_突。
當(dāng)前實(shí)現(xiàn)的引導(dǎo)程序,來自于類路徑。在引導(dǎo)時(shí),squbs通過類路徑掃描自動(dòng)檢測(cè)模塊。掃描到的cube自動(dòng)被檢測(cè)并啟動(dòng)。
Cube Jar包
所有cube由一個(gè)含有cube邏輯的頂級(jí)jar包表示。都必須有cube元數(shù)據(jù),存在于META-INF/squbs-meta.<ext>。支持的擴(kuò)展名包括.conf, .json, .properties。格式遵守Typesafe配置格式。
至少,cube元數(shù)據(jù)唯一標(biāo)識(shí)cube和版本,并聲明以下一個(gè)或多個(gè):
Actor:標(biāo)識(shí) squbs 自動(dòng)啟動(dòng)的眾所周知的actor。
Service:標(biāo)識(shí)一個(gè)squbs服務(wù)。
Extension:標(biāo)識(shí)一個(gè)squbs框架擴(kuò)展。擴(kuò)展入口點(diǎn)必須繼承于org.squbs.lifecycle.ExtensionLifecycle特質(zhì)。
配置解析
為一個(gè)cube提供application.conf,當(dāng)多個(gè)cube試圖提供它們內(nèi)部的application.conf會(huì)導(dǎo)致問題。合并此類配置的優(yōu)先級(jí)規(guī)則沒有定義。推薦cube僅提供一個(gè)reference.conf,并且可以被外部application.conf覆蓋以進(jìn)行部署。
眾所周知的actor
Well known actor只是Akka文檔所定義的Akka actors。它們由一個(gè)監(jiān)管actor(為每一個(gè)cube創(chuàng)建)啟動(dòng)。監(jiān)管者持有cube名稱。因此,任何well known actor有一個(gè)/<CubeName>/<ActorName>路徑,并且可以使用ActorSelection調(diào)用(使用/user/<CubeName>/<ActorName>)。
一個(gè)well known actor可以由單例actor或者路由器啟動(dòng)。為了將一個(gè)well known actor聲明為一個(gè)路由器,在actor聲明中增加with-router = true。對(duì)于well known actor路由器、調(diào)度器和郵件按照Akka文檔配置在reference.conf 或application.conf 。
下面是一個(gè)META-INF/squbs-meta.conf中的cube聲明,申明了一個(gè)well known actor:
cube-name = org.squbs.bottlecube
cube-version = "0.0.2"
squbs-actors = [
{
class-name = org.squbs.bottlecube.LyricsDispatcher
name = lyrics
with-router = false # Optional, defaults to false
init-required = false # Optional
}
]
init-required的參數(shù)用于需要發(fā)回其完全初始化狀態(tài)的actor, 以便將系統(tǒng)視為已初始化。有關(guān)啟動(dòng)/初始化掛鉤的完整討論, 請(qǐng)參閱運(yùn)行時(shí)生命周期和 API 文檔的啟動(dòng)掛鉤部分。
如果一個(gè)actor配置了with-router (with-router = true)和一個(gè)非默認(rèn)調(diào)度器,通常意味著在非默認(rèn)調(diào)度器上安排actor(即rootee)。路由器將假定well known actor名稱, 而不是 routee (你的actor實(shí)現(xiàn))。路由器上設(shè)置的調(diào)度器只會(huì)影響路由器, 而不是 routee。要影響 routee, 您需要為 routees 創(chuàng)建一個(gè)單獨(dú)的配置, 并將 "/*" 追加到該名稱。接下來, 您要將 routee 中的調(diào)度器配置為下面的示例。
akka.actor.deployment {
# Router configuration
/bottlecube/lyrics {
router = round-robin-pool
resizer {
lower-bound = 1
upper-bound = 10
}
}
# Routee configuration. Since it has a '*', the name has to be quoted.
"/bottlecube/lyrics/*" {
# Configure the dispatcher on the routee.
dispatcher = blocking-dispatcher
}
Akka文檔中記錄了路由器概念、示例和配置。
服務(wù)
在實(shí)現(xiàn)HTTP(s)服務(wù)章節(jié)對(duì)服務(wù)有詳細(xì)描述。在META-INF/squbs-meta.conf申明服務(wù)元數(shù)據(jù),如下例所示:
cube-name = org.squbs.bottlesvc
cube-version = "0.0.2"
squbs-services = [
{
class-name = org.squbs.bottlesvc.BottleSvc
web-context = bottles # You can also specify bottles/v1, for instance.
# The listeners entry is optional, and defaults to 'default-listener'.
listeners = [ default-listener, my-listener ]
# Optional, defaults to a default pipeline.
pipeline = some-pipeline
# Optional, disables the default pipeline if set to off. If missing, it is set to on.
defaultPipeline = on
# Optional, only applies to actors.
init-required = false
}
]
請(qǐng)看服務(wù)注冊(cè)有詳細(xì)描述。
擴(kuò)展
squbs中的擴(kuò)展是為了環(huán)境需要啟動(dòng)的低級(jí)別設(shè)施。擴(kuò)展初始化器需要繼承于org.squbs.lifecycle.ExtensionLifecycle特質(zhì)并覆蓋合適的回調(diào)。擴(kuò)展有很大的能力來內(nèi)省系統(tǒng),并提供額外的功能,而這些squbs本身并沒有提供。在同一個(gè)cube中,不能將擴(kuò)展與actor或服務(wù)組合在一起。
擴(kuò)展依次開始, 一個(gè)接著一個(gè)。擴(kuò)展的提供者可以在擴(kuò)展申明中提供一個(gè)序列號(hào)碼在擴(kuò)展啟動(dòng)時(shí)指定:sequence = [number]。如果沒有指定序列號(hào),則默認(rèn)為Int.maxValue。這意味著它將在所有提供序列號(hào)的擴(kuò)展之后啟動(dòng)。如果有多個(gè)擴(kuò)展不指定序列號(hào)或指定相同的序列號(hào), 則啟動(dòng)這些擴(kuò)展的順序是隨機(jī)的。關(guān)機(jī)順序與啟動(dòng)順序相反。
關(guān)閉squbs
squbs運(yùn)行時(shí),可以向Unicomplex()發(fā)送GracefulStop消息來正確關(guān)閉squbs。
默認(rèn)的啟動(dòng)主方法,org.squbs.unicomplex.Bootstrap,注冊(cè)了一個(gè)JVM關(guān)閉鉤子。因此,如果一個(gè)squbs應(yīng)用使用了默認(rèn)的main方法啟動(dòng),當(dāng)JVM收到SIGTERM時(shí),會(huì)優(yōu)雅的關(guān)閉。
如果某個(gè)其他監(jiān)視進(jìn)程負(fù)責(zé)關(guān)閉應(yīng)用程序 (例如 JSW), 則可以將 org.squbs.unicomplex.Shutdown 設(shè)置為正常關(guān)閉系統(tǒng)的主要方法。此Shutdown main 方法也向 Unicomplex 發(fā)送 GracefulStop 消息。
在某些用例中, 最好為關(guān)機(jī)添加延遲。例如, 如果負(fù)載平衡器每5秒鐘檢查一次應(yīng)用程序的運(yùn)行狀況, 并且應(yīng)用程序在運(yùn)行狀況檢查后關(guān)閉1秒, 應(yīng)用程序?qū)⒃诮酉聛淼?秒內(nèi)繼續(xù)收到請(qǐng)求, 直到下一次健康檢查為止;但是, 它無法滿足這些請(qǐng)求。如果使用上述方法之一 org.squbs.unicomplex.Bootstrap 或 org.squbs.unicomplex.Shutdown, 則可以通過在配置中添加以下內(nèi)容來增加關(guān)機(jī)的延遲:
squbs.shutdown-delay = 5 seconds
有了以上配置,向Unicomplex發(fā)送的GracefulStop消息將按計(jì)劃推遲5秒發(fā)送。
在收到GracefulStop消息后,Unicomplex actor將停止服務(wù)并傳播GracefulStop消息給所有的cube監(jiān)管者。每一個(gè)監(jiān)管者負(fù)責(zé)停止它c(diǎn)ube內(nèi)的actor(通過傳播GracefulStop消息給它的想要優(yōu)雅停止的孩子),確認(rèn)它們成功的停止或者在超時(shí)后發(fā)送一個(gè)PoisonPill,然后停止它自己。一旦所有的cube監(jiān)管者和服務(wù)停止,squbs系統(tǒng)關(guān)閉。然后,一個(gè)關(guān)閉鉤將被調(diào)用,來停止所有的擴(kuò)展并最終退出JVM。
web 容器目前沒有標(biāo)準(zhǔn)的控制臺(tái), 允許 squbs 的用戶自己構(gòu)建。通過向Unicomplex發(fā)送停止消息, web 控制臺(tái)可以提供正確的用戶關(guān)閉, 如下所示:
Unicomplex() ! GracefulStop