A mai napon elkezdük átvenni a Spring framework szépségeit... Kicsit utánakérdezve a témának, az volt a mondás, hogy ez egy elég masszív téma lesz. Ennek megfelelően mindenki jól kipihenten rengeteg koffeinnel felvértezve vágott neki a napnak.
A nap tanulságai 1:
A spring framework megértésének a kulcsa először is az Inversion of Control konténer mibenlétének az elsajátítása. Az IoC megfogalmazása a következő:
"Az Inversion of Control egy olyan irányelv, amelyben a vezérlés iránya megfordul a hagyományos procedurális programozáshoz képest."
Hát, kérem: ember legyen a talpán, aki ebből megérti, hogy miről van szó.
A magyar wikipedia szócikk már kicsit slendriánabb, de kicsit emészthetőbb:
"Az inversion of control (röviden IoC) főleg objektumorientált programozási nyelvekben használt technika a komponensek összeillesztésére, konfigurálására és kezelésére."
Tiszta? Nem? Oké, megmagyarázom:
Hagyományos megközelítés:
Álmos vagyok, tehát azt mondom:
- Hé! Kávéfőző! Főzz egy kávét! Itt van ez a két cukor! Ezt tedd bele. Itt egy kis tej. Ezt is kérem a kávémba! Add ide a kávét.
Inversion of control - elkérem a konténertől megközelítés:
Álmos vagyok, tehát azt mondom:
- Kávét!
Csodák csodájára a kezemben terem egy kávé. Nem tudom, ki főzte, és mi van benne, de én pont ezt a kávét szeretem.
Inversion of Control - konstruktor megközelítés:
Álmos vagyok. Szerencsére épp van egy tökéletes kávém.
Inversion of Control - Lasy loading megközelítés:
Elálmosodom. Odalép hozzám egy IoC konténer.
- Hé! Álmosnak tűnsz. Tessék, itt egy kávé!
Na jó! Fogalmazzuk meg komolyabban a problémát. Az IoC lényege, hogy elválasszuk a "hogyan?" kérdésre adott válaszokat a "mikor?" kérdésre adott válaszoktól. Egy-egy objektumnak ugyebár vannak dependenciái. Ezeket valamilyen módon be kell állítani. Ha nekem, mint objektumnak szükségem van egy loggerre, akkor nem nekem kell tudnom, hogy milyen logger hozok létre, az syslogba logol, vagy fileba, annak milyen egyéb függőségei vannak, hanem egyszerűen csak kérek az IoC konténertől egy loggert. Az ehhez szükséges beállítások, amelyek megmondják a kérdés hogyanságát, azok egy elkülönített helyen, valamiféle beállítás definíciós fileban dőlnek el.
Egy rövid példa kód a két megközelítésre:
IoC nélkül:
public class TestBankServiceIntegration {
@Test
public void testList() {
//given
List<String> expected = new ArrayList<>();
expected.add("Béla");
expected.add("Géza");
expected.add("Jenő");
BankService sut = new BankService(new BankDao());
//when
List<String> result = sut.listClients();
//then
Assert.assertEqualsNoOrder(result.toArray(), expected.toArray());
}
}
IoC konténerrel:
@ContextConfiguration(classes = AppConfig.class)
public class TestBankService extends AbstractTestNGSpringContextTests {
@Autowired
private BankService sut;
@Test
public void testGetClients() {
//given
List<String> expected = new ArrayList<>();
expected.add("Béla");
expected.add("Géza");
expected.add("Jenő");
//when
List<String> result = sut.listClients();
//then
Assert.assertEqualsNoOrder(result.toArray(), expected.toArray());
}
Mit látunk a fenti kódban ami érdekes lehet?
@ContextConfiguration(classes = AppConfig.class)
Tehát itt egy config class számunkra mágikus módon megmondja, hogy hogyan kell BankService osztályt példányosítani.
BankService sut = new BankService(new BankDao());
Az első kódban itt ugyebár a hagyományos módon példányosítottuk a BankService osztályunkat. Gondolom nem kell magyaráznom, hogy amennyiben több dependenciája van, amelyeknek további dependenciái vannak, akkor ez mennyire nehézkes lehet.
Ehelyett IoC konténerrel:
@Autowired
private BankService sut;
Voillá! Ennyi az egész.
Ha ezt megérted, akkor már csak meg kell tanulni, hogy hogyan lehet ezt a létrehozási mechanizmust konfigurálni XML-el, Java osztályokkal, annotációkkal, és milyen pontokon miféle módon avatkozhatsz bele a gyártási folyamatba, de ezek már a nagy felismeréshez képest részletkérdések.
A nap tanulságai 2.
A spring framework POJO-val (Plain Old Java Object) dolgozik. Viszlát, PHP-s világ. (Viszlát Plain Old PHP Objectek azaz POPÓ-k! :( ) Azt is megtudhadtuk, hogy a POJO annyiban különbözik a java bean-től, hogy nincsenek megkötései. Bármilyen számunkra kedves Java objektumot példányosíthatunk az IoC konténerünkben.
Aztán megtudhadtuk, hogy amennyiben egy POJO életciklusáról a spring gondoskodik, onnantól azt a POJO-t valójában Bean-nek (Spring bean) nevezzük. Valamint, hogy amennyiben szeretnénk könnyen beállítható propertyket használni, akkor nem baj, ha azokat a setPropertyName - getPropertyName konvenciót követő accessorokkal látjuk el. Valamint hogy ezekhez definiálhatunk a Jaba Bean világból származó PropertyEditorokat. De fontos tudni, hogy a spring POJO-val dolgozik, nem pedig bean-ekkel. :)
A nap tanulságai 3.
Egyelőre nem olyan ijesztő a spring, mint elsőre tűnt. Szép nagy anyagrész, amit 4 nap alatt kell átrágnunk, végre láttam a csapatban szünetben a kinti nagyon desinos de ülésre-fekvésre használhatatlan bútorokon szünetben fáradtságtól összeesve alvó embert, és a nap végére már többen a zombiság olyan szintjére jutottunk, hogy egymás agyának elfogyasztása hívogatóbb volt az amúgy nagyon ízletes minden nap ajándékba kapott tökmagos pogácsánál. Ezaz! Végre rock and roll! Várom a holnapi napot!