Zjednodušený pohled na CPS lifecycle
Zjednodušený pohled na CPS lifecycle
Zkopírovat odkaz na sekciŽivotní cyklus modulu
Pro tvůrce modulů je nutné znát lifecycle vlastního jádra CPS.
Zkopírovat odkaz na sekciStart aplikace
- při startu java kontejneru dochází k inicializaci CPS
- v konfiguraci projektu (sitemap.xml) je i konfigurace modulů (typicky modules.xml)
- CPS postupně moduly inicializuje, volá metodu setupModule
- po skončení inicializace všech modulů, volá na všech metodu prepareStartModule; v tuto chvíli může modul validovat, zda má splněny všechny závislosti na ostatních modulech, protože již všechny prošly úspěšně fází setupModule; zároveň pokud tyto závislosti splněné nejsou může ještě bezpečně selhat a způsobit tak selhání celého CPS a v případě reloadu zachovat předchozí instanci CPS funkční (viz. dále)
- nakonec moduly aktivuje, u všech modulů zavolá metodu startModule
Zkopírovat odkaz na sekciReinicializace
- probíhá za běhu java kontejneru na základě změny konfigurace (pravidelně se kontroluje čas změny konfigurace CPS)
- pro zvýšení bezpečnosti reinicializace je nejprve proveden pokus o inicializaci nové instance CPS včetně všech modulů (setupModule, prepareStartModule) - v případě selhání některého z modulů ve zmiňovaných metodách reload končí a v provozu zůstává původní (funkční) instance CPS
- pokud proběhne tato operace bez problémů je nové cps je aktivováno (CPSmanager poskytuje nové CPS)
- zároveň proces uzavře staré moduly - zavolá na modulech staré instance metodu prepareDestroyModule následně pak destroyModule
- v tuto chvíli tedy nejsou aktivní žádné moduly!
- v dalším kroku jsou nové moduly nastartovány metodou startModule - start modulu musí být maximálně bezpečný, pokud by v této chvíli nastala chyba nebude modul provozuschopný (původní instance modulů jsou již uzavřeny). Veškeré operace u kterých je předpoklad, že mohou selhat by proto měly být volány v půběhu setupModule - vyjímka v průběhu startu je pouze odchycena a zalogována.
- v dalším kroku je staré CPS uzavřeno, jsou provedeny servisní akce - start nového vlákna pro sledování konfigurace, start scheduleru
- nové CPS publikuje událost CpsReloadedEvent, cps je plně funkční
Start CPS poznáte nejlépe analýzou kódu ve třídě com.fg.webapp.cps.v1.core.config.CPSConfigurator. Reload v třídě com.fg.webapp.cps.v1.CPSmanager.
Zkopírovat odkaz na sekciDetailní popis
CPS zpracovává sitemap.xml a všechny odkazované konfigurační soubory ve pořadí daném v CPSConfigurator pomocí tzv. TagConfigurátorů. Ty jsou sekvenče zpracovány (na pořadí záleží). V zavěrečné fázi proběhne i ModulesConfigurator, který zpracuje obsah elementu modules a postupně pro každý modul volá jeho metodu setupModule.
ModulesConfigurator rozpozná třídu modulu buď přímou deklarací v atributu classname elementu module, nebo je třída odvozena ze známých plných názvů tříd navázaných na plný název elementu module - tj. CPS například ví, že třída modulu pro element mailmodule je com.fg.mail.cps.MailModule. Všechny tyto informace se dají najít v třídě ModulesConfigurator. S každým novým produktovým modulem třídu aktualizujte, aby nebylo nutné vypisovat classname.
Každý modul musí být unikátně rozlišen svým jménem - jako základ se bere jméno, které na sebe modul prozradí v metodě getModuleName, ale vývojář může nastavit jméno vlastní v atribut customName hlavního elementu modulu. Toto jméno modulu je klíčové např. pro sestavování URL v prohlížeči nebo jako základ exportovaného rozhranní modulu (viz. další kapitola).
Dalším důležitým atributem je required (default=true), který řídí, jak se má CPS zachovat, pokud selže inicializace modulu. V případě required=true selhání inicializace modulu způsobí selhání inicializace celého CPS, v opačném případě nikoliv.
Příklad konfigurace:
1 <!-- modul s uvedenou třídou, atribut required určuje chování v případě chyby -->2<module required="false" classname="com.fg.logger.LoggerModule"/> 3<!-- stejný modul, jeho třída je již uvedena v ModulesConfiguratoru, proto se nemusí vypisovat -->4<loggermodule/>
Veškerá konfigurace CPS je definována v sitemap.xml. Ten je možné rozdělit na libovolné množství menších souborů. Konfigurace modulu jsou tak typicky uloženy v modules.xml, které se do sitemap.xml includováno. Všechny konfigurační soubory jsou sledovány a pokud se změní datum poslední modifikace (vývojář změní konfiguraci) je spuštěn automatický refresh CPS (toto chování se může lišit dle konfigurace cps.reloadConfigMonitoredOnFile).
CPS je interně navrženo tak, aby dokázalo překonat co největší množství chyb způsobených vadnou konfigurací (např. nevalidní XML apod.) a zůstalo i nadále v provozu.
Jakmile CPS detekuje změnu v konfiguračním souboru, stále používá původní instanci CPS a paralelně provádí inicializaci instance nové - v jednu chvíli tedy může jeden a ten samý modul běžet 2x! Jedna instance se skutečně používá a druhá instance se právě inicializuje.
Pokud proběhne inicializace CPS na základě nové konfigurace v pořádku, nastaví se toto nové CPS jako hlavní a u staré instance CPS se spustí destroy sekvence.
V případě, že se nové CPS nepodaří nastartovat, systém bude v provozu - stále se používá poslední úspěšně nastartovaná CPS instance. Monitorovací thread se pokusí nové CPS nastartovat několikrát (maximálně 50x, pak se reinicializace zastaví). Toto chování počítá s tím, že se CPS nemuselo nastartovat kvůli stavu okolního prostředí, které se může v čase měnit, a proto start zkouší opakovaně.
Opravdu kritické místo celého principu je úplně první start CPS, kdy systém nemůže využít tohoto SAFE START principu z toho důvodu, že ještě nemá k dispozici žádnou běžící instanci CPS, ke které by se mohl v případě problémů s konfigurací vrátit. To pak typicky končí zobrazením chybové stránky při pokusu o zobrazení Edee rozhraní. Pak je nutné nalézt prvotní chybu v aplikačním logu (loguje do konzole, nebo souboru), je nutné počítat s tím, že problém často způsobuje další chyby, které jsou ale už jen následkem prvotního problému.
Zkopírovat odkaz na sekciNapojení na životní cyklus CPS
Na životní cyklus CPS je možné se napojit odkudkoliv pomocí registrace listeneru. Vaše třída musí implementovat rozhraní CpsInitListener, ve kterém jsou callbackové metody, které CPS zavolá ve chvíli, kdy provádí inicializaci / refresh CPS (cpsCreated / cpsReloaded). Registrovat listener je možné odkudkoliv pomocí:
1 CPSmanager.getInstance().addCpsInitListener(listener)Při použití této metody je možné, že k navázání k registranci listeneru dojde až v době, kdy je již CPS vytvořené. V takovém případě by se instance CPS nepředala až do prvního refreshe. Proto od CPS 2.0.8 existuje ještě metoda addAndUpdateCpsInitListener.
1 CPSmanager.getInstance().addAndUpdateCpsInitListener(listener)Ta zajistí zavolání metody CpsInitListener.cpsCreated hned po registraci listeneru. Při použití této metody je možné, že dojde k zavolání cpsCreated metody dvakrát.
V praxi není tento mechanizmus nutné (ani doporučené) využívat - typické problémy jsou řešeny na obecné úrovni (např. pomocí podpory dané Spring moduly).