Spring opravdu není kontejnerem?
Nemám moc rád kontejnery, mají tu nepěknou vlastnost, že nad nimi nemáte úplnou kontrolu. Zavoláte nějakou metodu kontejneru, ona zavolá metodu která je spuštěná v jiném vlákně, ta vyvolá výjimku, celý kontejner lehne a vaše aplikace s ním. V lepším případě, lehne vaše aplikace a kontejner žije dál. S trochou dobrého návrhu, vytáhnete aplikaci znovu do funkčního stavu, ale o tom proč aplikace spadla nemá ani páru.
To je hlavní důvod proč volím pro své aplikace Spring s tím, že http (a jiné protokoly) spravuji z něj.
Bohužel, není zlato co se blýská a i Spring má své meze. Dneska, při testování DAO objektu, jsem vesele vyvolal exception pomocí toho, že jsem jeden objekt navázal na dva sessiony (to teda nevím jak se mi povedlo, ale časem to snad vyřeším). Chyba která z testu vypadla: org.springframework.orm.hibernate3.HibernateSystemException. Samozřejmě jsem ji neměl ošetřenou (nevěděl jsem že může vypadnout), takže objekty které byly vytvořené pro testování v databázi zůstaly. Metoda onTearDown se nezavolala, takže při dalším spuštění testu lehnul na duplicitě některých unikátních polí.
To se ví, to jednoho naštve, musíte jít do databáze a všechno odmazat, nehledě na to, že taková chyba by měla být odchycena. Tak jsem se ji snažil odchytit, nepovedlo se. Ani uzavření metody, která chybu vyvolala do try catch bloku nepomohlo. Jal jsem se hledat jak je něco takového možné.
Je to jasné, metoda je vyvolána ve vláknu které obhospodařuje připojení k hibernate. Tohle vlákno vytvořil už kontext springu. Takže exception propadne až na úroveň objektu, který vlastní sprinový kontext (prostě spustilo spring).
Takže ani všechny try catch bloky světa vám nepomůžou a chybu budete lovit až někde na dně aplikace.
Asi to má své odůvodnění, stejně tak jako nejspíš někde ve specifikaci, bude informace o tom, jaké vlákna spring spouští. Jen já myslel, že jede všechno sekvenčně a že si vlákna spravuju sám. Pletl jsem se, škoda.
Bohužel jsem ani nenašel žádný návrhový vzor, který by to řešil. Jediné co mně napadá je zase commandy řízený přístup do databáze. S tím, že vlákno držící commandy, které ještě nebyly provedeny bude vytvořeno majitelem spring contextu. To je jediná šance jak se dostat do místa kde chyba vznikla a chybu nějak ošetřit. On je totiž dost běs, že nemůžete zavolat v návaznosti na chybu rollback, prostě protože tam kde vám spadne chyba, už nemáte ani tušení jaký session máte rollbackovat.
P.S.: A po chvíli testování Vám lehne databáze na množství limbo transakcí, prostě jsem dneska měl dobrý den