本文首發於泊浮目的專欄: https://segmentfault.com/blog...
隨着ZStack的版本迭代,其能夠掌管的資源也愈來愈多。但新增模塊的結構卻仍是大體相同,此便是ZStack的經典設計模式——這套模式也被開發者稱爲ZStack三駕馬車。java
以PrimaryStorage爲例,其APIMsg的真正邏輯處理第一站就是PrimaryStorageManagerImpl
。git
若是是對特定的PrimaryStorage進行操做,將會經過相應的Factory
得出對應類型並轉發至相應的Base
:github
private void passThrough(PrimaryStorageMessage pmsg) { PrimaryStorageVO vo = dbf.findByUuid(pmsg.getPrimaryStorageUuid(), PrimaryStorageVO.class); if (vo == null && allowedMessageAfterSoftDeletion.contains(pmsg.getClass())) { PrimaryStorageEO eo = dbf.findByUuid(pmsg.getPrimaryStorageUuid(), PrimaryStorageEO.class); vo = ObjectUtils.newAndCopy(eo, PrimaryStorageVO.class); } Message msg = (Message) pmsg; if (vo == null) { String err = String.format("Cannot find primary storage[uuid:%s], it may have been deleted", pmsg.getPrimaryStorageUuid()); bus.replyErrorByMessageType(msg, errf.instantiateErrorCode(SysErrors.RESOURCE_NOT_FOUND, err)); return; } PrimaryStorageFactory factory = getPrimaryStorageFactory(PrimaryStorageType.valueOf(vo.getType())); PrimaryStorage ps = factory.getPrimaryStorage(vo); ps.handleMessage(msg); }
PrimaryStorageFactory
是一個接口,在此基礎上有各式各樣的實現:如Local
、Ceph
、NFS
等。segmentfault
public interface PrimaryStorageFactory { PrimaryStorageType getPrimaryStorageType(); PrimaryStorageInventory createPrimaryStorage(PrimaryStorageVO vo, APIAddPrimaryStorageMsg msg); PrimaryStorage getPrimaryStorage(PrimaryStorageVO vo); PrimaryStorageInventory getInventory(String uuid); }
這就像現實中的模型同樣——在ZStack中能夠有PrimaryStorage,並且能夠有不一樣類型的PrimaryStorage:設計模式
PrimaryStorage:架構
這在軟件工程中便是一種分離領域(Layered Architecture)的具象。應用層對應ZStack的ManagerImpl,而Base更像是領域層。ide
應用層的定義應該是:ui
而在ZStack中,的確也像上面說的如此。在源碼中咱們能夠看到,對實例操做的API所有被轉發到了Base層去,而Manager這裏handle的每每是一些過濾性、Get型API,如APIListPrimaryStorageMsg
、APIGetPrimaryStorageMsg
、APIGetPrimaryStorageTypesMsg
等。spa
Manager便是API(這裏API不單單是APIxxxMsg,同時包含用於通訊的內部Msg。注意,它們都implements
自Message這個接口)的入口,以及用於管理服務的生命週期。debug
定義:
以PrimaryStorageBase爲例,其自己對應了DB中的一條記錄,而且在改變狀態後也Refresh本身。並對操做單獨實例的Msg進行handle。
雖然分了層,而且關係是鬆散的。可是各個層之間也是須要通訊的,那麼層與層之間只能是單向的。上層能夠直接使用或操做下層元素,方法是經過調用下層元素的公共接口,保持對下層元素的引用(至少是暫時的),以及採用常規的交互手段。而若是下層元素須要與上層元素通訊,則須要採用另外一種通訊機制——好比回調或者Observers模式(在ZStack中便是ExtensionPoint)。
咱們仍是以PrimaryStorageBase爲例。在其作連接操做時,邏輯以下:
private void doConnect(ConnectParam param, final Completion completion) { thdf.chainSubmit(new ChainTask(completion) { @Override public String getSyncSignature() { return String.format("reconnect-primary-storage-%s", self.getUuid()); } @Override public void run(SyncTaskChain chain) { changeStatus(PrimaryStorageStatus.Connecting); connectHook(param, new Completion(chain, completion) { @Override public void success() { self = dbf.reload(self); changeStatus(PrimaryStorageStatus.Connected); logger.debug(String.format("successfully connected primary storage[uuid:%s]", self.getUuid())); RecalculatePrimaryStorageCapacityMsg rmsg = new RecalculatePrimaryStorageCapacityMsg(); rmsg.setPrimaryStorageUuid(self.getUuid()); bus.makeLocalServiceId(rmsg, PrimaryStorageConstant.SERVICE_ID); bus.send(rmsg); tracker.track(self.getUuid()); completion.success(); chain.next(); } @Override public void fail(ErrorCode errorCode) { tracker.track(self.getUuid()); self = dbf.reload(self); changeStatus(PrimaryStorageStatus.Disconnected); logger.debug(String.format("failed to connect primary storage[uuid:%s], %s", self.getUuid(), errorCode)); completion.fail(errorCode); chain.next(); } }); } @Override public String getName() { return getSyncSignature(); } }); }
而不一樣的connectHook
都有不一樣的實現。
在抽象等級上,PrimaryStorageBase是比圖中的這些Base高的。而這類具象Base能夠Message返回Success或者Fail使高層Base作出不一樣的決策。
繼續,在PrimaryStorageBase中,其中handle APIAttachPrimaryStorageToClusterMsg
的地方會作事件發送:
extpEmitter.preAttach(self, msg.getClusterUuid());
其會發送向:
在這裏,一個Base經過了Observers模式向某個ManagerImpl發送了事件,實現了下層往上層的通訊。
在大型軟件工程中,咱們一般會給這樣的應用劃分層次。分別在每層中進行設計,使其具備內聚性而且只依賴於它的下層,而下層與上層也只有鬆散的耦合。這使得模型含義豐富,結構清晰。也使得整個應用架構更加茁壯。