Zobrazují se příspěvky se štítkemSpring framework. Zobrazit všechny příspěvky
Zobrazují se příspěvky se štítkemSpring framework. Zobrazit všechny příspěvky

29. září 2013

Architektura integračního řešení

V dnešním článku se opět vracím k mému poslednímu projektu, na kterém jsme realizovali nového virtuálního operátora, viz článek Zkušenosti s Apache Camel. Já konkrétně jsem měl na starosti integrační část celého řešení.

Integrační část je centrálním bodem celého řešení, a proto musí být vždy dostupná. Kromě jiného musí splňovat ještě tyto požadavky:

  • spolehlivost
  • škálovatelnost
  • výkonnost
Pro úplnost uvedu přehled externích systémů, se kterými integrační platforma komunikuje:
Při návrhu aplikací a vlastně i při jejich realizaci se snažím držet mého přesvědčení, že nemá cenu dělat nic zbytečně dopředu, dokud není jasné, že je to opravdu potřeba. Pamatuji si na dobu, kdy jsem se snažil vše řešit co nejobecněji a naivně jsem si myslel, že až se ukáže v budoucnu, že to bude potřeba, tak to na to už bude připravené. Bohužel k tomu nikdy nedocházelo - buď se změnily požadavky nebo k tomu ani nedošlo, aby se něco dodělávalo. Jsem přesvědčený o tom, že pokud jsou věci jednoduché (tedy jednoduchá a jasná architektura), pak je to i srozumitelné a lépe udržovatelné. 

S tímto přístupem jsme navrhovali i toto integrační řešení:
  • operační systém CentOS 6.4 64bit
  • Apache Tomcat 7 - krásný příklad, jak v jednoduchosti je síla. Nevidím žádný (technický) důvod, proč používat něco složitějšího.
  • PostgreSQL 9 - databázi používáme pro persistenci vstupních zpráv, se kterými dále pracujeme a zaručujeme se o jejich zpracování. Mě osobně by se zde více líbilo JMS (např. Apache ActiveMQ nebo RabbitMQ), ale výběr databáze byl již dán, takže jsem s tím musel pracovat jak to bylo dáno. Obával jsem se zde úzkého výkonnostního hrdla, zejména v momentě, kdy se více ESB instancí bude "prát" o nové zprávy ke zpracování, ale zatím se ukazuje, že moje obavy byly zbytečné.
  • Load balancing je prováděn komponentou apache http serveru mod_proxy_balancer pomocí round robbin algoritmu. Balancing zajišťuje rozkládání zátěže na jednotlivé nody a primárně je  použit z důvodu vysoké dostupnosti ESB nodu, jelikož v případě výpadku jednoho z ESB nodů automaticky na daný chybný node přestane směrovat requesty.
  • Samotný apache http server je zároveň provozován také na dvou nodech, mezi kterými je pak pohyblivá IP adresa, která je pak aktivní pouze na jednom ze serverů a přes tento server je pak primárně směřován provoz. Apache na druhém serveru je tak pouze ve stavu standby a přes něj by byl směrován provoz až v případě migrace této „pohyblivé“ IP adresy na tento server, ze kterého je pak prováděn balancing stejným způsobem na oba dva aktivní aplikační servery čímž je zajištěna vysoká dostupnost systému.
  • Na HTTP proxy je zakončena zabezpečená SSL komunikace, dále směrem k aplikačnímu serveru je již komunikace realizována pouze pomocí HTTP protokolu.
Co se týče výběru aplikačního stacku, tak základ je tvořený knihovnou Apache Camel, která zajišťuje samotné routování zpráv. Zbylé věci jsou řešeny Spring knihovnami:
  • Spring Framework tvoří základní stavební kámen pro konfiguraci aplikace
  • Spring Security pro zabezpečení webové admin části a pro zabezpečení komunikace s externími systémy
  • Spring Web Services jako hlavní Camel komponenta pro komunikaci pomocí webových služeb

18. února 2011

Proč jsem nepoužil Spring Batch?

Když jsem si srovnal zadání na mém posledním projektu, tak vše na první pohled nasvědčovalo tomu, že bude vhodné použít Spring Batch, další projekt z rodiny Springů. Za to jsem byl moc rád, protože jsem již delší dobu hledal příležitost, abych tento zajímavý projekt vyzkoušel.

Na začátku jsem Spring Batch znal jen z několika článků, a proto, když se mi v zadání projektu objevovala slova jako "dávkové zpracování, škálovatelné, rychlé, vícevláknové, robustní, procesy", tak se mi to automaticky spojilo s tímto Springovským projektem. Nastudoval jsem referenční příručku a přidal do mé aplikace.

Bohužel žádný Spring Batch ve výsledné aplikaci nenajdete. Když se teď na to koukám již z dvouměsíčním odstupem, tak se musím trochu smát, jak jsem opravdu chtěl za každou cenu Spring Batch využít, jak jsem se to snažil napasovat na všechny možné podporované "patterny" z dávkového zpracování dat apod. Nakonec jsem Spring Batch kompletně opustil a vystačil si jen ze základními funkcemi Spring frameworku pro scheduling a práci s táskama - Task Execution and Scheduling.

Výhody použití Spring Batch:

  • Spring Batch pomáhá s řešením dávkového zpracování dat, což má svá určitá specifika ve srovnání s "normálními" aplikacemi. Pokud náš řešený problém dokážeme napasovat na podporované scénáře, tak máme vyhráno a můžeme Spring Batch použít.

  • dávkové zpracování hodně souvisí se správně zvolenou strategií transakcí a zde podle mě nabízí Spring Batch největší přidanou hodnotu, kdy jsme většinou zcela oproštěni od řízení transakcí.

  • dávkové zpracování ve většině případů vyžaduje nějaké vstupní funkce na čtení a pak výsledné zapisovače. Spring Batch obsahuje čtečky pro flat soubory, XML soubory, databáze atd., data je možné zapisovat do databáze přes JDBC, Hibernate nebo JPA. Samozřejmě není problém si cokoliv upravit či dopsat - já sám jsem si napsal čtečku dat z mailové serveru.

  • Spring Batch nabízí funkce na opakování a znovu-spuštění dílčích operací (repeat a retry). To vše díky tomu, že Spring Batch si ukládá všechny informace k tomu, aby mohl jakýkoliv proces, krok procesu znovu spustit nebo ho pustit opakovaně.
    Spring Batch vyžaduje určitý datový model, do kterého si ukládá informace o aktuálním procesu, kroku, zpracovaných datech. Ukládání těchto dat není povinné, ale pak je řada funkcí nedostupná.

  • Spring Batch Admin - pokud necháme Spring Batch ukládat běhová data, pak můžeme využít webovou aplikaci pro zobrazení těchto dat, pro jejich administraci, včetně funkcí na znovu-spuštění procesů či jednotlivých kroků.

  • jak už jsem psal, dávkové zpracování má svoje specifika včetně řady "paternů" pro různé scénáře a pokud naše řešení dokážeme napasovat na tyto paterny, tak budeme mít aspoň nějakou jistotu, že daný problém řešíme dobře.


Já jsem Spring Batch nevyužil z těchto důvodů:
  • zažil jsem to poprvé, ale měl jsem od zákazníka celkem přesné zadání, jak by workflow aplikace mělo vypadat. Neměl jsem tedy úplně možnost si to udělat podle sebe. (ono by to šlo napasovat, vše jde, ale došel jsem k názoru, že to udělám mnohem jednodušeji bez Spring Batch, viz dále)

  • nepotřeboval jsem žádné repeat a retry funkce, žádné držení stavu, žádné informace o počtu procesů, kdy běžely, žádnou webovou vizualizaci dat atd.

  • po nějakém zhodnocení jsem došel k závěru, že jediné co by mi Spring Batch přinesl, tak by bylo transakční řízení, které jsem navíc potřeboval také nepatrně jinak, než bylo standardně nabízenou.


I když Spring Batch ve výsledné aplikaci není, tak i přesto jsem se s ním detailně seznámil, řadu věcí vyzkoušel a pokud budu zase někdy něco řešit dávkově, tak určitě budu přemýšlet o jeho využití.

15. února 2011

Znáte Spring Data (JPA)?

Již jsem o tom psal na Twitteru, ale myslím, že si to zaslouží trochu větší a delší pozornost, tak to píši ještě sem.

Pod hlavičkou firmy SpringSource se v poslední době objevilo spoustu nových projektů a jedním z nich je i projekt Spring Data. Rozsah projektu je celkem velký:

The primary goal of the Spring Data project is to make it easier to build Spring-powered applications that use new data access technologies such as non-relational databases, map-reduce frameworks, and cloud based data services. A secondary goal is to provide additional support for relational database technologies such as Oracle RAC and convenience classes for Java generic based repository classes.


Mě osobně nejvíce zaujal podprojekt Spring Data JPA, o kterém vyšel pěkný úvodní článek na blogu.

Snad každý si vytvořil nějaké svá rozšíření pro práci s Hibernatem nebo JPA, aby nemusel pořád dokola psát jednoduché dotazy na načtení jednoho objektu, všech objektů, jejich uložení atd. Právě toto vše a mnohem více nabízí tento projekt Spring Data JPA, takže budu moci s klidem zahodit své řešení a začít využívat toto od Springu.

21. května 2010

Auto-wiring a možná řešení při více beanech stejného typu

Pokud používáme auto-wiring (dále předpokládám auto-wiring podle typu), tak se nám lehce může stát, že máme více beanů (instancí) stejného typu. V tomto případě Spring vyhodí výjimku, protože nemá žádný návod, jak tuto situaci vyřešit.

Zejména v testech se mi toto stává velice často, protože mám bean produkčního kódu, ale pro testy chci použít implementaci určenou pouze pro testy.

Příklad:

context.xml
<bean id="b1" class="FooImpl" />

context-test.xml
<bean id="b2" class="FooTestImpl" />

@ContextConfiguration(locations = {"classpath:/context.xml", "classpath:/context-test.xml"})
public void FooTest() {
@Autowired
private Foo foo;
}


Mám několik možností, jak tento problém řešit:

  • nadefinuji druhý (testovací) bean se stejným ID jako produkční bean a jelikož se testovací bean inicializuje jako druhý (z tohoto důvodu je velice důležité pořadí inicializace souborů Spring konfigurace), tak se přepíše (override) a ve Spring kontejneru bude ve výsledku pouze jeden bean - v tomto příkladu FooTest. Stejně to bude fungovat i když u obou beanů vynechám atribut ID. Pak se ID generují automaticky (viz implementace BeanNameGenerator) a budou tedy také stejná.

  • použiji anotaci @Qualifier a poradím Springu, jakou beanu má přesně vybrat. Ovšem ještě musím upravit konfiguraci beanu b2.

    <bean id="b2" class="FooTestImpl">
    <qualifier value="test">
    </bean>

    @Autowired
    @Qualifier("test")
    private Foo foo;

    Také to jde bez úpravy konfigurace a bez použití tagu <qualifier>. Pokud tento tag není definován, pak defaultní chování je takové, že se vygeneruje qualifier s hodnotou ID daného beanu. Mohu tedy pak napsat následující (ovšem pro tento přístup spíše doporučuji použití anotace @Resource, která je pro to určena):
    @Autowired
    @Qualifier("b2")
    private Foo foo;

  • použití anotace @Resource je pro tento případ vhodnější nez @Qualifier, zejména z pohledu sémantiky obou anotací.
    @Resource(name = "b2")
    private Foo foo;

  • použití primary atributu. Tento atribut dostupný pro každý bean říká, že se jedná o primární (první, doporučený) bean pro auto-wiring, pokud bude více adeptů stejného typu. Tuto vlastnost jsem objevil až nedávno, protože zmínka o ní je celkem zapadlá v dokumentaci.

  • za určitých podmínek by bylo možné ještě použít atribut autowire-candidate u produkčního beanu b1 a nastavit ho na false. Tím pak bude pro auto-wiring určen jen bean b2.

Tak jednoduchý problém a tolik možností řešení :). Já osobně nejčastěji používám řešení s primary a nebo s přepisováním definice beanu.

14. září 2009

Distribuované transakce bez JEE kontejneru

Dlouho dobu jsem si myslel, že pokud potřebuji řídit transakce přes více datových zdrojů, pak se nikdy neobejdu bez plnohodnotného JEE kontejneru resp. serveru.

Před pár lety jsem na projektu potřeboval propojit do jedné transakce události ze dvou datových zdrojů (databáze, souborový systém) a bez znalosti dané problematiky jsem si sám napsal jednoduchý mechanismus, který mi dokázal v 98% případů zaručit, že se uloží buď obě události a nebo žádná. Ve zbylých dvou procentech případů to nefungovalo, ale to mi z pohledu logiky aplikace moc nevadilo. Pro mě bylo důležitější, že jsem si vystačil pouze se Springem a Tomcatem, a že to celé běhalo celkem rychle.

Proč o tom píšu? Nedávno jsem si všimnul, že samotný Spring bude mít tento mechanismus zabudovaný přímo v jádře.

Já se vždy snažím vyhnout "těžkým" řešením při návrhu aplikací a zde je hezky vidět, že i distribuované transakce se dají řešit "lehkou" cestou. Je ale potřeba si předem jasně říci, co je pro nás nejdůležitější - zda 100% spolehlivost bez výjimek nebo rychlost celého transakčního systému nebo výběr technologií. Nejde bohužel splnit všechny tři kritéria najednou k plné spokojenosti, je potřeba si vybrat jedno a ostatní k tomu přizpůsobit.

Doplňující články:

28. června 2009

Konec Spring Modules, nastupuje Spring Extensions

Opožděně jsem si všimnul, že projekt Spring modules již není aktivně podporován (je deprecated) a místo toho je doporučeno přejít na Spring Extensions.

Spring Modules obsahuje rozšíření, moduly, pro jednodušší napojení Spring frameworku na knihovny třetích stran. Kromě toho nabízí pro určité oblasti odstínění od konkrétních technologií, např. obsahuje jednotné rozhraní pro kešování bez ohledu na to, jaká implementace se vybere. Já osobně jsem používal moduly integrující Lucene, EhCache a Jackrabbit.

Již delší dobu jsem měl pocit, že projekt "moc neběží", proto mě ani konec nijak nepřekvapil. Ono je opravdu hodně těžké sledovat všechny ty verze různých knihoven a k tomu pořád dokola rozšiřovat své API a svoji funkčnost. Takto zní i oficiální stanovisko:
"Spring Modules was developed to serve a similar goal and was very successful. In fact, it was too successful and grew beyond anybody's expectations. As such, Spring Modules isn't really flexible enough or scaleable enough to manage a large number of independent projects. Spring Modules has now reached end of life. The modules that are still undergoing active development may be ported to Spring Extensions.".

Spring Extensions mají jiný koncept fungování. Snaží se přitáhnout třetí strany k tomu, aby oni vytvářeli tyto rozšíření (takže něco jako SourceForge, Google code). Rozdíl je zejména v tom, že kromě potřebné infrastruktury budete mít podporu během celého vývojového cyklu včetně podpory při propagaci projektu. Asi budete i zaplaceni - roli interního sponzora jsem moc nepochopil, ale když jim dáte práva na zdrojový kód, když s nimi uzavřete smlouvu, tak bych nějakou odměnu čekal.

Zatím v přehledu aktuálních projektů není ani jeden z původních Spring Modules a doufám, jak se uvádí, že dojde k přesunu.

31. března 2009

Spring MVC: GET kontroler

Dlouho jsem neuváděl žádný můj zdrojový kód, tak to dnes zkusím napravit. Spring MVC nabízí pro zpracování požadavku GET dva základní kontrolery:

  • ParameterizableViewController - jednoduchý kontroler, který pouze vyžaduje zadání cílového view, které se následně zobrazí.

  • BaseCommandController - kontroler, který pracuje s parametry requestu přes commandy. Tedy kontroler automaticky mapuje parametry requestu do atributů objektu (commandu), je možné využívat validace, bindery apod.

V každé aplikace resp. projektu se hodí mít nějaké své předky-kontrolery, které mohou zprvu být prázdné, ale vždy se časem ukáže, že je potřeba mít nějakou společnou funkcionalitu nebo společná data pro většinu nebo všechny kontrolery. My jsme se na projektu rozhodli mít dva předky-kontrolery, jeden pro práci s formuláři (zpracování POSTu) a jeden pro práci s GETem. A právě u GETu jsem narazil na to, že bych rád měl možnost výběru - jednou mi stačí si vytáhnout parametr přímo z requestu a jindy využiji command s validací. Takže z tohoto důvodu jsem udělal následující mix dvou výše uvedených kontrolerů. Pro úplnost ještě musím zmínit použití rozhraní IDataModelProvider, které slouží k předávání modelu resp. dat společných jak pro GET, tak pro POST kontrolery.


/**
* Zakladni implementace kontroleru pro zobrazovani stranek pres GET metodu, tj. zobrazeni
* JSP stranky, pripadne predani promennych na stranku.
*
* <p>Kontroler muze pracovat ve dvou "rezimech" - s commandem a bez nej.
* Pokud chceme pracovat s commandy a tedy mapovat parametry requestu do commandu, tak pak
* je vhodne v podtride implementovat metodu
* {@link #handle(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, Object, org.springframework.validation.BindException)}
* a nastavit tridu commandu {@link #commandClass}.
*
* <p>Pokud nam staci pristup k parametrum requestu (bez commandu), tak pak je vhodne implementovat
* v podtride metodu {@link #handleRequestInternal(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)}.
* Toto chovani je defaultni.
*
* @see BaseFormController
*/
public class BaseGetController extends AbstractCommandController {
private static final Logger logger = Logger.getLogger(BaseGetController.class);

private IDataModelProvider dataModelProvider;
private String viewName;
private boolean supressBinding = false;
private boolean supressValidation = false;

protected void initApplicationContext() {
if (this.viewName == null) {
throw new IllegalArgumentException("Property 'viewName' is required");
}
}

/**
* Metoda resi, zda se bude pracovat s commandem (a tedy request parametry se budou
* napojovat na command) a nebo zda se bude pracovat bez commandu (a tedy je nutne pracovat samostatne
* primo s parametry requestu).
*
* <p><b>Tato metoda je vhodna k implementaci v podtridach, pokud nepracujeme s commandem
* a staci nam pristup k requestu.</b>
*/
protected ModelAndView handleRequestInternal(HttpServletRequest request,
HttpServletResponse response) throws Exception {
if (getCommandClass() == null) {
//pracujeme bez commandu
this.supressBinding = true;
this.supressValidation = true;
return this.handle(request, response, null, null);
}
else {
//pracujeme s commandem
return super.handleRequestInternal(request, response);
}
}

/**
* Metoda vklada spolecna data do vysledneho modelu.
*
* <p><b>Tato metoda je vhodna k implementaci v podtridach, pokud pracujeme s commandem</b>.
* Pokud neni {@link #commandClass} definovano, tak pak vstupni parametry <i>command</i> a <i>errors</i> jsou null.
*/
protected ModelAndView handle(HttpServletRequest request,
HttpServletResponse response,
Object command,
BindException errors) throws Exception {
ModelAndView mav = new ModelAndView(getViewName());

mav.addAllObjects(dataModelProvider.getModelData());

if (logger.isDebugEnabled()) {
logger.debug("BaseGetController returns: " + mav);
}

return mav;
}

protected boolean suppressBinding(HttpServletRequest request) {
return this.supressBinding || super.suppressBinding(request);
}

protected boolean suppressValidation(HttpServletRequest request, Object command) {
return this.supressValidation || super.suppressValidation(request, command);
}

public void setDataModelProvider(IDataModelProvider dataModelProvider) {
this.dataModelProvider = dataModelProvider;
}

/**
* Set the name of the view to delegate to.
*/
public void setViewName(String viewName) {
this.viewName = viewName;
}

/**
* Return the name of the view to delegate to.
*/
public String getViewName() {
return this.viewName;
}
}

10. února 2009

Proč pořád webové služby?

K dnešnímu článku mě inspiroval můj bývalý kolega, který se jednou naučil webové služby a od té doby je používal úplně všude - bez ohledu na to, že by se mnohdy dalo použít lepší (rozuměj jednodušší, efektivnější) řešení.

Napadá mě zde analogie s EJB. Mnoho lidí se naučí EJB a od té doby je používají bez ohledu na to, zda skutečně EJB kontejner v aplikaci potřebují. Podobné je to i s webovými službami. Webové služby jsou nezastupitelné v komunikaci mezi různými platformami. Jinak řečeno, pokud nemáme všechny komunikující systémy pod kontrolou, tak vždy bude asi nejlepší používat webové služby. Existují i jiné "multiplatformí" protokoly jako např. binární Hessian nebo textový Burlap, ale určitě nejsou tak rozšířené jako webové služby. Co se ale týče jednoduchosti použití a hlavně rychlosti komunikace, tak zde webové služby hodně ztrácejí oproti jiným řešením.

Pokud ovšem máme komunikující systémy pod kontrolou a navíc se jedná o Java aplikace, tak bych webové služby nevolil. V těchto případech většinou nejde o vystavení nějaké trvalé služby, ale o vzdálené volání metod. Pro tyto případy nejvíce ocením jednoduchost použití (tj. jednoduchost při nastavení řešení plus pracnost spojená s úpravou objektů pro přenos) a rychlost komunikace.

Pro tyto případy mám výborné zkušenosti s řešením od Springu - Spring remoting. Osobní zkušenosti mám s použitím HttpInvokeru - víceméně řešení postavené na Java serializaci s přenosem po HTTP. S tímto řešením jsem neměl jediné problémy, fungovalo suprově. Jen jsem musel dořešit jednu věc - kromě vlastních objektů se přenášely i objekty knihoven třetích stran, které občas obsahovaly neserializované objekty (většinou se jednalo o výjimky). V tomto případě jsem si pomohl AOP - vytvořil jsem si AOP vrstvu nad vzdálenými službami, která kontrolovala, zda všechny přenášená data jsou opravdu serializovatelná.

Na posledním projektu používáme Hessian z důvodu požadavku na co největší výkon resp. na přenos co nejmenšího množství dat. Tuto volbu jsme provedli (lépe řečeno mojí kolegové) na základě vlastních měření a ze zkušeností uvedených v tomto článku. S Hessianem pracuji zatím velice krátce, ale již se mi podařilo narazit na problémy s přenosem dat (až budu znát přesné příčiny a řešení, tak to uvedu v komentáři k tomuto článku).

U Spring remotingu se mi také libí, že je to postavené nad DispatcherServletem (stejně jako třeba Spring MVC), takže mohu využívat spoustu společných věcí, zejména Spring security pro zabezpečení.

Pokud nevíte, který protokol vybrat pro vaše řešení, tak si přečtěte výše uvedený článek (zejména závěrečné shrnutí) a nebo doporučení uvedené v dokumentaci Springu.

21. ledna 2009

Spring AOP: Dynamic Proxies vs. CGLib proxies

Pokud jste se někdy více ponořily do AOP resp. vytváření AOP proxy objektů ve Springu, tak jste určitě museli řešit, jaký přístup vlastně zvolit - zda vytvářet proxy objekty pomocí knihovny cglib nebo pomocí JDK.

Oba přístupy mají svoje specifika resp. výhody nebo nevýhody - zde je odkaz na článek, který to celé pěkně shrnuje.


Pokud všechny objekty inicializuje Spring kontejner, tak pak je vytváření AOP proxy objektů zcela automatické (např. pro řízení transakcí) a programátor se víceméně nemusí o nic starat. Někdy je ale potřeba mít vytvořené AOP proxy kolem objektů, které Spring nemá pod kontrolou, např. doménové objekty, které vytváří ORM knihovna nebo nějaké vlastní struktury, kde používáte new.

Spring nabízí následující dvě možnosti řešení:

Více o obou možnostech je uvedeno v dokumentaci ke Springu - Programmatic creation of @AspectJ Proxies a Using AspectJ to dependency inject domain objects with Spring.

8. ledna 2009

Spring certifikace

Mám to! :)

Tento týden jsem napsal testy a získal certifikaci "SpringSource Certified Professional".

Rád bych se s vámi podělil o nějaké mé postřehy či zkušenosti z přípravy a samotného testu.

Člověk musí nejdříve získat "povolení", aby vůbec mohl dělat testy. Povolení lze získat buď tím, že budete absolvovat jejich kurzy na Core Spring a nebo, že prokážete vaší zkušenost se Springem. Já jsem se vydal tou druhou cestou - přišel mi ze SpringSource formulář k vyplnění, na jehož základě mi pak poslali číslo kupónu, které jsem následně použil u certifikační agentury. V dotazníku se mě například ptali na mé dosavadní zkušenosti se Springem na projektech (musel jsem uvést nějaké referenční osoby jak z mé firmy, tak od zákazníka, pro jakého zákazníka to bylo, jaké části Springu jsem využil, jaké jiné open-source knihovny jsem použil), zda nějak přispívám do Spring komunity, zda nějak pomáhám v osvětě Springu apod. Celkově jsem z toho měl pocit, že si tak nějak dělají přehled o tom, na co se vlastně Spring používá, pro jak velké zákazníky a kdo vlastně žádá o tu certifikaci. Nemám žádnou zpětnou vazbu, že by byl někdo z mnou uvedených lidí kontaktován za účelem ověření informací. Doposud jsem dělal pouze certifikace u Sunu, proto mě toto celkem zaskočilo, nicméně jsem prošel a mohl jsem na zkoušku.

Ukázkové testy jsem nenašel žádné (ani na černém trhu :) ) a musel jsem si vlastně vystačit jen s dokumentací od Springu - JavaDoc a referenční dokumentace. SpringSource nabízí přehled oblastí k certifikaci a nějaké ukázkové otázky z testu - sice tam nejsou stejné odpovědi jako v reálném testu, ale otázky tak nějak sedí, bohužel jen tak ze třech oblastí. Ještě jsem našel nějaké podklady zde, ale to je spíše přehled nějakých základních termínů.

Samotný test má 50 otázek, je na to 90 minut. Každá oblast má pět otázek, což aspoň pro mě nebylo zrovna příjemné, protože o Spring Core nebo o Spring MVC toho vím hodně, ale takové JMX nebo JMS jsem nikdy moc (bohužel) nepoužíval. Vše ale mělo stejnou váhu. Také jsem se dost bál všech těch názvů tříd a rozhraní, které Spring má. Teď již vím, že jsem se spoustu věcí učil zbytečně, je opravdu potřeba znát jen ty hlavní, jako např. JdbcTemplate, HibernateDaoSupport, JmsTemplate atd. Otázky byly hodně zaměřeny na obecné znalosti spojení Springu a dané technologie (např. v čem všem mi může pomoci Spring ORM modul při práci s Hibernate), na často používané termíny (např. definice advice nebo aspektu) a někdy i na samotné technologie (např. jaké komunikační protokoly jsou definovány ve specifikaci JSR-160 pro JMX?). Je pravda, že někdy jsem se musel podívat i do jiné dokumentace než od Springu.

Kdo už někdy psal nějaké podobné testy, tak ví, že je potřeba si dát pozor na každé slovíčko, jak v otázce, tak v odpovědích. Každá otázka měla žádnou, jednu nebo všechny správné odpovědi.


PS: Někde jsem našel, že letos přibudou ještě další certifikáty:

  • SpringSource Web Technologies Professional
  • SpringSource Advanced Methodologies Professional
  • SpringSource Integration Professional
  • SpringSource Application Management Professional

20. června 2008

OSGi: Použít nebo nepoužít?

Hned na začátku článku musím říci, že jsem velký fanda modulárních systémů a OSGi především. Ale to hned nemusí znamenat, že OSGi budu používat vždy a za všech okolností - pro mě je důležité za použitím jakékoliv technologie vidět určitý přínos a tedy důvod, proč danou technologii použít. Samozřejmě to také musí být vyvážené rozumnou pracností.

O OSGi je v poslední době hodně slyšet. Málokdo asi ví, že tato věc vznikla už někdy v roce 1999, takže se nejedná o žádnou novinku. Určitě znáte resp. používáte Eclipse nebo IBM WebSphere - to jsou asi dva hlavní představitelé produktů, které jsou postaveny nad OSGi. Přijde mi, že to správné buzzword z toho udělal až Spring, protože Spring si OSGi vybral jako nosné řešení pro své všechny projekty, pro svoji vlastní aplikační serverovou platformu SpringSource Application Platform. Základem je projekt Spring Dynamic modules, který zase funguje jako nástavba na "čistým" API OSGi a nabízí spoustu ulehčení - prostě standardní Spring :). Možná ještě více publicitě OSGi pomohl sám Sun, který přišel s něčím podobným přímo do JVM - Java Module System. Do teď není zcela jasné, které řešení nakonec zvítězí, ale řekl bych, že OSGi má v současné době navrch.

Cílem článku není vysvětlovat možnosti OSGi, na to jsou jiné weby. Tento článek shrnuje mé osobní poznatky z průzkumu OSGi, jakožto možné platformy pro vývoj naší nové aplikace. Připravujeme vývoj nové webové aplikace (možná by se dalo říci i produktu), která technologicky nevybočuje nijak z průměru (Spring, Hibernate, JSF). Nejedná se také o aplikaci nijak zásadně kritickou, spíše o podpůrný nástroj pro menší skupinku lidí ve firmě. Aplikace to nebude (aspoň na začátku) nijak rozsáhlá.

A teď jsme před rozhodnutím, zda použít nebo nepoužít OSGi. Ještě jsme se finálně nerozhodli, ale spíše to vidím tak, že OSGi pro tento projekt zatím nepoužijeme. Mám k tomu následující důvody:

  • Sice jsem psal, že OSGi bude mít příští rok 10 let, ale v oblasti serverové Javy tak dlouho nepůsobí. Nejdříve tato technologie byla vyvíjena pro mobilní aplikace (to je záruka, že OSGi je opravdu lightweigth řešení), poté se adaptovala v oblasti standalone aplikací (např. Eclipse, kontejner Equinox) a teď v poslední době je snaha o adaptaci v oblasti serverových aplikací. To je trochu složitější, protože jsou potřeba minimálně dva kontejnery - pro Javu resp. servlety a pro OSGi. Jsou plně podporovány kontejnery Tomcat, Jetty a prý další nejsou problém, ale nikde jsem k tomu moc informací nenašel. OSGi kontejner může být vložen do webového kontejneru a naopak, více zde. Jak je možné integrovat do OSGi+webového kontejneru stávající MVC řešení? Co když budu chtít použít další kontejner pro EJB? Tak v tomto vůbec jasno nemám.

  • Abych mohl aplikaci modularizovat pomocí OSGi, tak pak musím mít vše rozdělené do tzv. bundlů - moje i všechny knihovny třetích stran musí být bundly. Vznikají tedy různá repository (např. 1, 2), kde je možné si stáhnout bundly známých knihoven, např. pro Hibernate, Jakarta Commons apod. Nicméně určitě všechny knihovny tam v podobě bundlů nenajdete. Pak jsou dvě možnosti - buď si počkáte až bundle bude a nebo si bundle z jar souborů vytvoříte sami. Buď ručně nebo s pomocí nástroje Bnd.

  • Pokud tedy budu mít OSGi aplikaci, tak mohu za běhu aplikace instalovat, nahrávat, rušit jednotlivé moduly resp. bundly, mohu efektivně řešit verzování apod. Na to se dá říci jen SUPER. Ale potřebuji to tak zrovna pro mojí aplikaci? Nikdy jsem to zrovna nepotřeboval a pro tuto aplikaci to asi také nepotřebuji. Aplikace není kritická, takže ji v pohodě mohu celou otočit. Ani velká moc nebude, takže upgrade bude otázka chvilky. Na druhou stranu mě hned napadá, že se bude jednat o aplikaci s instalacemi a úpravami u více zákazníků, což by se hezky dalo řešit pomocí modulů. Také hromadný upgrade všech instalací z jednoho místa by nemusel být k zahození.

  • Nikdy neříkej nikdy - možná přijde doba, kdy z malé počáteční aplikace bude velký systém, který bude potřebovat modularizovat. Nemám s tím žádnou zkušenost, ale řekl bych, že nebude tak velký problém z již existující aplikace vytvořit OSGi aplikaci. Příkladem mohou být např. Spring projekty, které jsou nyní plně OSGi - jednotlivé jar soubory jsou zároveň bundly exportující a importující potřebné služby resp. balíky.

Nějaké zdroje k OSGi:

1. dubna 2008

JSF a Spring - postup o krok dále

Velice mě zaujala prezentace o možnostech integrace JSF a Springu, hlavně tzv. Spring-centric JSF Integration Approach.

Uvedu jen základní informace (vše ostatní je v prezentaci):
JSF plugs into Spring as a View implementation
• Integrates with Spring MVC and Web Flow
• FacesServlet is not used

Spring is used
• As the managed bean provider
• As the request dispatcher
• As the navigation handler
• As the state manager
• As a lightweight JSF component library

Mimo jiné mě také zaujalo toto - "The ability to inject the result of an EL expression evaluation into a managed bean" - to by mělo být dostupné ve Springu 3.0.

Pro mě jako Springaře je to dobrá zpráva, protože na mě kolegové pořád tlačí s JSF a Seamem a takhle budu mít zase o něco lepší alternativu k jejich návrhům.

28. února 2008

Způsoby konfigurace Springu

Když se mluví o Springu, tak to má hned každý spojený s tím, že se vše konfiguruje pomocí XML. Pravděpodobně je to kvůli tomu, že opravdu v minulosti (do verze 2.0) nebyla jiná schopná možnost konfigurace, ale to již dneska v žádném případě neplatí.

Jakými způsoby můžeme tedy konfigurovat springovské aplikace?

XML

Vždy aspoň trochu té konfigurace v XML budeme potřebovat, minimálně říci, že budeme konfigurovat např. pomocí anotací. Já osobně mám konfiguraci v XML celkem rád, protože vše mám vytažené na jedno místo, hned vidím všechny ty možné závislosti. V porovnání s anotacemi nemusím skákat mezi třídami a zjišťovat, jak je to vše vlastně propojené. To má podle mě také výhodu s ohledem na úpravu konfigurace. Na druhou stranu musím uznat, že někdy je to "až moc upovídané" - to se částečně zlepšilo s nástupem namespaců. Nejvíce mi to přijde upovídané ve webové vrstvě okolo kontrolerů, tak jsem tuto část aplikace začal konfigurovat pomocí anotací.

Anotace

Od druhé verze Springu je možné používat anotace. Anotace jsou v poslední době "sexy", takže tento styl se bude využívat asi hodně často. Spring se také snaží držet hesla "convention over configuration", což ve spojení s anotacemi vytváří velice rychlý a efektivní způsob konfigurace. Jak už jsem zmiňoval, velice se mi toto osvědčuje pro webovou vrstvu aplikace.

Java konfigurace

Tento způsob konfigurace není standardní součástí Spring frameworku, ale je vyvíjen bokem jako Spring Java Configuration Project. Tento způsob bych asi použil tehdy, když bych potřeboval mít dynamicky měnící se konfiguraci, tj. za běhu např. měnit nastavení parametrů připojení k databázi. Výhodou určitě také je to, že vše je v Javě - máme doplňování kódu, kontroly syntaxe a všeho možného, refaktoring.
Zdá se mi ale, že tento projekt se nějak zastavil. Pamatuji si na několik přednášek na konferenci SpringOne v červnu minulého roku, kde toto prezentovali jako novinku a zajímavou možnost do budoucna. Je o devět měsíců později a projekt je pořád ve stejném stavu. Myslím si, že přeci těch způsobů konfigurace je celkem dost a že malinkato se to překrývá s projektem Spring dynamic modules.

Properties

Hned na začátku říkám, že nemám na mysli využití PropertyPlaceholderConfigurer, ale PropertiesBeanDefinitionReader . Jedná se tedy o způsob konfigurace pomocí properties souborů.
Tento způsob konfigurace je ve Springu už asi jen z historických důvodů, na nových projektech tento způsob už asi nikdo nepoužije.


Na závěr bych dodal, že jednotlivé způsoby konfigurace lze libovolně křížit, pro určitou část můžeme použít anotace, pro jinou XML apod.
Volba způsobu konfigurace závisí na každém z nás, každý preferuje jiný způsob. Proto mi přijde celkem nefér, že se často vytýká Springu jeho upovídanost, protože je to každého věc a pokud budu chtít, tak té konfigurace bude opravdu minimum.

Články k příspěvku:
More on Java Configuration
Spring Java Configuration Moving Ahead

17. prosince 2007

Novinky ze Springu

Moc často nekomentuji různé události, ale teď mi to nedá. Právě se koná konference The Spring Experience, což jsou spolu s konferencí SpringOne dvě nejvýznamnější konference věnované přímo Springu.
Právě na této konferenci se objevily velice zajímavé novinky z dílny firmy SpringSource (dříve Interface21):

  • doplnění Spring portfólia o Spring Integration, o část, která by měla pomoci při vývoji servisně-orientovaných aplikací. Podle mého názoru je dneska skoro nezbytností mít něco podobného v portfóliu, v době, kdy se každý ohání slovíčkami jako SOA, webové služby, integrace apod. V brzké době by projekt měl být publikován a někdy ve druhém čtvrtletí roku 2008 by měla být verze 1.0. Více si můžete přečíst na Team blogu SpringSourcu.

  • SpringSource Application Management Suite - podle dostupných informací, které se mi podařilo najít, by to měla být taková nádstavba nad Springem, která bude zobrazovat běhové informace o aplikaci jako např. kolik proběhlo transakcí, kolik zpráv se zpracovalo, kolik aktivních beanů je v aplikaci apod. Já osobně to chápu tak, že místo abychom museli vytvářet MBeany pro přístup k velmi často potřebných informacím, tak budeme moci použít tento Application Management Suite, který nám bude automaticky nabízet standardní sestavu pro každou aplikaci.

  • SpringSource Certification Program - toto je velice zajímá informace, o které se již tak trochu mluvilo na konferenci SpringOne v letošním roce. Na certifikace jsou různé názory, ale určitě lze říci, že je to krok správným směrem, pokud chceme aby se Spring čím dál více prosazoval a používal mezi velkými hráči jako jsou například banky. Je ale otázka, kdy se to dostane až k nám do Čech - v USA to začne na konci ledna.

Více si můžete přečíst v tomto článku.

5. listopadu 2007

Přednáška: transakční strategie (nejen ve Springu)

Nechci pořád posílat odkazy na nějaké cizí prezentace, ale v poslední době jsem jich viděl celkem hodně a ta poslední mě hodně zaujala. Nedá mi to tedy, abych vás na ní neupozornil, protože fakt stojí za to.

Je to přednáška na téma "Transaction Management Strategies in Mission-Critial Enterprise Applications". Přednáška nejprve obecně popisuje problematiku transakcí (parametry transakcí, nativní vs. JTA transakční manažeři), poté jsou popisovány možnosti při využití Spring frameworku a nakonec jsou uvedeny různá doporučení s ohledem na typ aplikace nebo aplikačního serveru. Co přednáška neřeší jsou transakce ve spojení s JMS.

Jednou z hlavním myšlenek a doporučení je používání nativních transakčních manažerů (HibernateTransactionManager, DataSourceTransactionManager, ...) v porovnání s JTA transakčními manažery. Samozřejmě pokud to situace dovolí, tedy když naše aplikace nevyžaduje propagaci transakcí (např. když aplikace běží přes více JVM) nebo koordinaci více datových zdrojů najednou (např. při použití více databází). Poslední bod je ovšem možné řešit bez použití "plného" J2EE aplikačního serveru pomocí standalone řešení (Geronimo transakční manažer, JOTM, ...).

1. listopadu 2007

Přednáška: spring v produkčním nasazení

Pokud nesledujete pravidelně novinky na stránkách Spring frameworku, tak mám pro vás zajímavou informaci - firma Interace21 začala nabízet interaktivní webové prezentace o Springu.

Tento týden proběhla první z těchto přednášek na téma "Spring in production". Kromě samotné přednášky, která trvala hodinu, byla možnost stáhnutí dokumentu popisující Spring v reálném produkčním nasazení (tedy víceméně to samé, co zaznělo na samotné přednášce). Snad všechny různé typy a triky jak zvýšit výkon nebo něco optimalizovat jsem již slyšel, ale ještě jsem neviděl takto komplexní dokument, který by vše uceleně popisoval. Kromě těchto optimalizačních rad dokument obsahuje souhrnný popis toho, co se děje v průběhu inicializace Spring aplikace.

Chtěl jsem ten dokument přiložit do blogu, ale na poslední chvíli jsem si všimnul, že ten dokument není volně k šíření. Pokud o něj tedy máte zájem, tak se budete muset přihlásit k prezentacím o Springu (a snad ho bude ještě možné stáhnout) a nebo počkat, až se tento dokument objeví na stránkách Interface21 (tuto informaci jsem zachytil během chatu v průběhu přednášky).

Nejsou ještě známy témata dalších přednášek, jen doufám, že nějaké stejně zajímavé budou i nadále. Super by bylo, kdyby se ty přednášky časem objevily i na Parleys nebo podobných serverech.

5. října 2007

AOP proxy objekty - volání metody v rámci jedné třídy

Dlouho jsem přemýšlel nad nějakým výstižným názvem tohoto příspěvku, ale nic moc jsem nevymyslel. Zkusím tedy popsat o co přesně jde.
Mám třídu, která má dvě metody. Obě metody se mají pouštět v transakci, každá metoda může nebo nemusí mít svoje vlastní nastavení transakční definice. Pro účely ukázky jsem si vymyslel následující příklad:

public interface DocumentFacade {
/**
* Metoda pridava vice dokumentu.
*/
public DocumentIdsFacadeResult addDocuments(DocumentsDTO doc);

/**
* Metoda pridava pouze jeden dokument, tato metoda je volana metodou addDocuments().
*/
public DocumentIdsFacadeResult addDocument(DocumentsDTO doc);
}

<bean id="DbTransactionInterceptor"
class="org.springframework.transaction.interceptor.TransactionInterceptor">
<property name="transactionManager" ref="dbTransactionManager" />
<property name="transactionAttributes">
<props>
<prop key="add*">PROPAGATION_REQUIRED,-Exception</prop>
</props>
</property>
</bean>

<bean id="serviceProxyCreator"
class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="beanNames">
<list>
<idref bean="documentFacade" />
</list>
</property>
<property name="interceptorNames">
<list>
<idref bean="DbTransactionInterceptor" />
</list>
</property>
</bean>

Z požadavků zákazníka vyplývá následující chování - pokud se bude vkládat více dokumentů, tak výsledek každého vložení dokumentu bude nezávislý (atomický) od ostatních vložení dokumentů. Když tedy budu přidávat dva dokumenty a během prvního se objeví nějaká chyba ve zpracování, tak vložení druhého dokumentu to nemůže ovlivnit. Jinak řečeno každé volání metody addDocument() bude ve své vlastní transakci.

Pro méně zkušené uživatele AOP (mezi ně se řadím i já) se může zdát, že předcházející požadavek je automaticky vyřešen nastavením transakcí - obě metody odpovídají nastaveným transakčním atributům (viz bean serviceProxyCreator). A zde je právě kámen úrazu. Pokud bychom volali jednotlivé metody nezávisle (např. z kontroleru), tak vše bude chodit bez problémů, ale vzhledem k tomu, že jedna metoda je volána z druhé metody stejné třídy resp. objektu, tak nedochází ke vstupu do objektu přes proxy (jsme pořád v tom samém objektu) a tudíž se neaktivuje transakční nastavení pro druhou metodu. Pro náš příklad to znamená, že vše se provede pouze v jedné transakci definované pro první metodu, tedy addDocuments().
Toto samozřejmě není problém jen transakcí, ale obecně všech AOP proxy objektů.

Jaká jsou možná řešení? Z dostupných informací jsem našel následující řešení:
  • Refaktorovat strukturu volání, tak aby nedocházelo k volání v rámci jedné třídy. Toto řešení se může nakonec ukázat jako nejvíce použitelné pro případy, které nelze vyřešit následujícím řešením.

  • Použít programové transakční vymezení pomocí TransactionTemplate. Toto je celkem elegantní řešení pokud nechceme "uměle" refaktorovat kód. Problém může ovšem být v případě, kdy potřebujeme nastavit transakci přes více zdrojů (např. databáze a JCR). Pro tento případ je pak nutné použít JtaTransactionManager.
    Možná by šla ještě vnořená implementace TransactionTemplate, ale toto jsem nezkoušel. Velká výhoda nastavení transakcí ve Springu je ta, že infrastrukturní věci jako transakce mohu definovat deklarativně a mimo vlastní kód - zde tyto výhody ztrácím.

  • Programově se dostat k proxy objektu a uměle nasimulovat volání metody z vně objektu. Přesně tomuto řešení nerozumím (více informací je možné nalézt zde), ale každopádně je to už řešení, které je pevně spojeno se Springem a vlastním kódem.


Já osobně jsem zatím vždy použil druhý způsob.

28. září 2007

Fulltextové vyhledávání (Lucene, Compass)

V dnešní době je celkem běžný požadavek na fulltextové vyhledávání v aplikaci. Uživatel aplikace si již nechce pamatovat všechny ty možné atributy a vybírat možné hodnoty - on se prostě potřebuje dostat k cíli na základě toho co zná a už bez ohledu na vlastní uložení dat.
Pokud se někdo rozhodne zahrnout fulltextové vyhledávání do své aplikace, tak první co bude muset vyřešit je, zda použít vestavěnou podporu fulltextu v databázi či vybrat nějakou knihovnu, která bude fulltext implementovat. Pro obě volby existují určité výhody a nevýhody.
Mezi výhodami řešení pomocí knihoven se často uvádí:

  • výkonnější než databázové řešení

  • plně konfigurovatelné

  • plně pod kontrolou

  • databázové řešení lze použít pouze pro omezený doménový model, kdežto knihovna v tomto ohledu žádné omezení nemá


Mezi výhody databázového řešení patří:
  • většinou automaticky součástí databázových serverů

  • snadné a lehké použití bez nějakého velkého nastavování

  • někdy i lepší vlastnosti než řešení pomocí knihovny, např. podpora češtiny


Pro vysvětlení posledního bodu bych rád dodal některá fakta: já osobně používám knihovnu Apache Lucene (verze 2.0). K hodnocení této knihovny se dostanu dále v článku, ale co už bych chtěl uvést již zde, je horší podpora češtiny. Není problém samozřejmě ukládat český text s diakritikou a i vyhledávat s diakritikou, ale již není možné počítat s ohýbáním slov. To je možné ve většině případů řešit pomocí zástupného znaku *, ale není to úplně stoprocentní. Na druhou stranu např. Microsoft nabízí český a slovenský jazykový modul do svého SQL serveru, který tuto funkcionalitu nabízí. Žádnou osobní zkušenost s tím ale nemám.

Apache Lucene a Spring modules

Jak už jsem zmínil, tak ve svém projektu používám knihovnu Apache Lucene. Nejsem odborník přes fulltextové techniky, ale myslím si, že Lucene nabízí jedno z nejlepších (možná i nejlepší) řešení pro fulltextové vyhledávání na platformě Java. Další důvod, proč jsem toto řešení kdysi vybral bylo množství dokumentace a informací na webu a také podpora ve Spring modules, což zase posouvá práci s touto knihovnou o úroveň výše. S knihovnou Lucene resp. Spring modules jsem naprosto spokojený - co se týče nastavení datového modelu, co se týče použití (ale to hlavně díky Spring modules) a také výkonnost se ukazuje jako velice dobrý. Aplikaci teď budeme nasazovat do pilotního provozu u zákazníka, takže na závěrečné zhodnocení je ještě čas.

Compass

Apache Lucene a Spring modules bude znát asi většina lidí, ale již méně je známý Compass - Java Search Engine Framework. Já osobně jsem si této knihovny všimnul na konferenci Spring One a dokonce jsem našel ke stažení vlastní prezentaci.
Nemám s tímto frameworkem zatím žádnou osobní zkušenost, ale některé klíčové vlastnosti jsou velice zajímavé:
  • Framework je postaven nad Apache Lucene. Compass lze používat nejen jako nástavbu nad Lucene, která řeší některé jeho nedostatky jako např. chybějící podpora transakcí, příliš nízkoúrovňové API, nepříliš rychlá aktualizace indexů a možnost ukládání indexů pouze na souborový systém (pozn. nízkoúrovňové API a ukládání indexů řeší již Spring modules).

  • Integrace se Springem a Hibernate

  • Compass umožňuje si stávající datový model (nebo jeho část) napamovat pro účely fulltextového vyhledávání. K tomuto je možné použít konfiguraci pomocí XML nebo anotací.

  • Změna datového modelu se může automaticky promítat v indexech.


Pokud někdo máte zkušenost s jazykovým modulem do MS SQL nebo jiných databází či přímo s Compassem, budu jedině rád, když se podělíte o vaši zkušenost.

19. září 2007

Přehled článků a knih o Springu

Kamarád se na mě obrátil s prosbou, zda bych mu mohl poslat nějaké odkazy ke Springu, že by se rád s tím seznámil. Řekl jsem si, že když už mu budu něco posílat, tak to můžu dát rovnou na blog.
V posledních dvou letech jsem si přidal do oblíbených pár článků a přečetl jsem nějaké knížky. Tyto informace bych chtěl zde tedy publikovat.

Články


Knihy

  • Agile Java Development with Spring, Hibernate and Eclipse - tuto knížku jsem četl nedávno a nedala mi nic nového. Jsem z ní spíše zklamaný, protože jsem měl pocit, že autor tam toho chtěl uvést co nejvíce, ale nic pořádně. Měl jsem také dojem, že kdybych začínal od začátku, tak nemám šanci se to podle toho naučit. Takže tuto knížku moc nedoporučuji.

  • Spring in Action - tuto knížku jsem celou nečetl, spíše jsem jí v rychlosti prošel. Pro začátečníky mi přijde dobrá, protože obsahuje celkem srozumitelný výklad o vlastnostech Springu včetně příkladů. Na druhou stranu knížka obsahuje skoro to samé jako referenční dokumentace ke Springu.

  • POJO in Action - tato knížka není jen o Springu, ale i přesto do tohoto seznamu patří. Kniha obsahuje spoustu zajímavých informací a příkladů a je z ní cítit, že autor zkušenosti má a více o čem píše. Tuto knížku vřele doporučuji.

  • J2EE Design and Development - tato knížka je taková moje programovací bible. Sice byla vydána před pár lety, ale pořád většina uvedených myšlenek je aktuální. V této knížce uvádí zakladatel Springu Rod Johnson základní myšlenky pro vývoj aplikací, podle kterých pak vlastně vznikl samotný Spring.


Pokud někdo máte jiné zajímavé odkazy na články nebo jste četly nějaké zajímavé knížky, tak budu jedině rád, když je uvedete v komentářích k tomuto článku.

3. září 2007

Více prostředí pomocí Springu, implementace

Tímto článkem navazuji na první úvodní část Více prostředí pomocí Springu, úvod. Bez zbytečných úvodních slov se pustím do popisu implementace.

Vhodně zvolená adresářová struktura

Spring framework nabízí rozsáhlé možnosti konfigurace. Já jsem v mém řešení využil hlavně tyto vlastnosti:
  • PropertyPlaceholderConfigurer - patří mezi dobré zvyklosti, že různé parametry k nastavení (např. připojení k DB, nastavení Hibernate, cesty k adresářům) se nastavují přes properties soubory. Z pohledu konfigurace to má tu velkou výhodu, že já mohu mít společnou konfiguraci pro všechny prostředí, ale konkrétní parametry konfigurace (např. parametry pro připojení do DB) mohu mít definovány v každém prostředí zvlášť.
  • Dědičnost bean - definici beany si mohu označit jako abstraktní s tím, že až bude jasné přesné nastavení (tedy pro určité prostředí), tak se beana donastaví
  • Collection merging - tato vlastnost souvisí s předchozí vlastností a umožňuje mi spojovat kolekce z rodiče a potomků. Zase s ohledem na konfiguraci prostředí si např. nadefinuji společný propertyConfigurer a v jednotlivých prostředích ho rozšířím o další properties soubory.
  • Lazy inicializace - díky této vlastnosti mohu mít beany, které se budou inicializovat pouze tehdy, když budou potřeba. Zase bych uvedl příklad použití: jedna z našich aplikací má lokální a centrální část. Aplikace to byla vyvíjena jako jedna, ale s tím rozdílem, že v každé částí běžely jiné služby.
Příklad vhodné adresářové struktury může být například následující:
src
config
env
ANECT
DEVELOP
CUSTOMER
TEST
java
config
common
Adresář common obsahuje společnou konfiguraci, jednotlivé podadresáře v adresáři env představují konkrétní prostředí. Názvy adresářů pro jednotlivá prostředí musí odpovídat názvům položek v enum tříde:
/**
* Enum of all environments.
* Enum names have to correspond with names of directories.
*
* @author pjuza
*/
public enum Environment {
DEVELOP("development"),
CUSTOMER("Customer deployment"),
ANECT("ANECT testing deployment");

private final String description;

Environment(String description) {
this.description = description;
}

public String getDescription() {
return description;
}
}

Načítání konf. souborů pro dané prostředí

Informace o prostředí, které se má spouštět nastavuji v properties souuboru:
#environment ('ANECT', 'DEVELOP', 'CUSTOMER')
environment = DEVELOP

#version
version = 0.5

Pro načítání konf. souborů jsem si vytvořil třídu EnvironmentUtils, která mi načítá soubory z jednotlivých adresářů.
/**
* Util class for choosing right configuration files for selected
* application part and environment.
*
* @author pjuza
*/
public class EnvironmentUtils {
protected final static Log logger = LogFactory.getLog(EnvironmentUtils.class);

private static final String ENV_PROP = "environment";
private static final String VERSION_PROP = "version";

private static ResourceBundle configProps;

static {
//load config properties
try {
configProps = ResourceBundle.getBundle("config/config");
}
catch (Exception e) {
logger.fatal("Error occured during application initialization.", e);
}

logger.info("We're running in version: " + getVersion());
}


/**
* Method returns conf. files for application initialization.
* @return conf. files
*/
public static String[] getConfigLocations() {
List files = new ArrayList();
// our regular application context files
files.add("classpath:/config/common/sp_*.xml");
// our env. specific context files
files.add("classpath:/config/env/" + getEnvironment() + "/sp_*.xml");

return files.toArray(new String[]{});
}

/**
* Method returns right environment.
* @return environment
*/
public static Environment getEnvironment() {
String envValue = configProps.getString(ENV_PROP);
Environment env = Environment.valueOf(envValue);

logger.info("We're running in environment: " + env.getDescription());

return env;
}


/**
* Method gets version of application.
* @return version
*/
public static String getVersion() {
return configProps.getString(VERSION_PROP);
}
}
Všimněte si, že soubory se načítají v pořadí od obecných nastavení (adresář common) směrem ke konkrétnímu nastavení pro dané prostředí. Také se mi vyplatilo si zavést nějakou konvenci pro pojmenování konf. souborů.

Úprava inicializace Springu

Poslední co nám zbývá je upravit inicializaci Springu tak, aby načítal konf. soubory dle naší implementace v EnvironmentUtils. Proto je potřeba si napsat vlastní implementaci ContextLoaderListener a ContextLoader. Zde uvádím jejich implementace:
/**
* Custom context loader listener.
*
* @author pjuza
*/
public class EnvironmentAwareContextLoaderListener extends ContextLoaderListener {

@Override
protected ContextLoader createContextLoader() {
return new EnvironmentAwareContextLoader();
}
}

/**
* Custom context loader for loading specific configuration files according to
* environment.
*
* @author pjuza
*/
public class EnvironmentAwareContextLoader extends ContextLoader {
protected final static Log logger = LogFactory.getLog(EnvironmentAwareContextLoader.class);

@Override
protected WebApplicationContext createWebApplicationContext(ServletContext servletContext,
ApplicationContext parent)
throws BeansException {
Class contextClass = determineContextClass(servletContext);

if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
throw new ApplicationContextException("Custom context class [" + contextClass.getName() +
"] is not of type [" + ConfigurableWebApplicationContext.class.getName() + "]");
}

ConfigurableWebApplicationContext wac =
(ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
wac.setParent(parent);
wac.setServletContext(servletContext);

// Start change:
wac.setConfigLocations(EnvironmentUtils.getConfigLocations());
// End change

wac.refresh();
return wac;
}
}
Toto je základní implementace, kterou je možné dále rozšiřovat dle potřeb. Jak už jsem naznačoval, naše poslední aplikace měla dvě části, takže načítání konf. souborů bylo ještě komplikovanější. Ale ve Springu není nic nemožné :-).