Včera jsem si četl dokumentaci k WebBeans. A ač opravdu nemám rád EJB a i k anotacím se stavím dost rezervovaně, docela mě to zaujalo. Je tam pár zajímavých nápadů, které mi docela rozšířily obzory.
Ale abych začal od začátku. WebBeans jsou projekt, který se s největší pravděpodobností dostane do Java EE 6 jako JSR-299. Ideově to celé vychází ze Seamu, ostatně dané JSR vede Gavin King.
Nebudu se zabývat úvodem, radši se podívejte do originální dokumentace nebo sem (česky). Radši napíšu jen co mě zaujalo. No nejvíc asi to, že se díky WebBeans mohou stát EJB i JSF snadněji použitelnějšími. Stejně jako Seam propojují obě technologie, což se může docela hodit. Navíc podporují injektování i normálních POJO, což je taky velký skok vpřed. Nicméně to vypadá, že se EJB nezbavíme, budeme je muset použít pro deklarativní transakce a podobně. Ale proč ne, ve verzi 3.1 vypadají docela snesitelně.
Vlastní anotace
Z technického hlediska mě zaujala míra použití anotací. Z dokumentace to vypadá, že se každý problém dá vyřešit napsáním si vlastní anotace. Doposud jsem anotace spíš jen pasivně používal než je vytvářel. Ale ve WebBeans bude tvorba vlastních anotací na denním pořádku. Uvedu příklad. Představte si, že z nějakého zvrhlého důvodu potřebujete injektovat do bean náhodné číslo. První co potřebujete udělat, je nějaká továrna. Ve WebBeans vyrobíte normální POJO a k metodě přidáte @Produces. Tím frameworku řeknete, že to je továrna na inty. No ale int není zrovna moc konkrétní typ a je velká pravděpodobnost, že se vám v aplikaci objeví továren na inty víc, takže je musíte nějak rozlišit. Tak si napíšete vlastní anotaci @Random.
@ApplicationScoped public class Generator { private Random random = new Random( System.currentTimeMillis() ); @Produces @Random int next() { return random.nextInt(100); } }
Když pak chcete injektnout náhodné číslo někam jinam, tak jen použijete tu samou anotaci.
@Random int randomNumber
Není to nic světoborného, Spring to umí taky, ale tady je to primární způsob konfigurace. Navíc můžete nad deklaraci beany hodit anotaci, že je jen pro testovací prostředí, nebo pro zákazníka z Kanady a framework se vám postará o to, aby se použily pro dané prostředí vhodné implementace.
InjectionPoint
Další zajímavá věc je InjectionPoint. Představte si následující kód.
@Current Logger log;
Tím říkám, že chci injektnout logger. Obvykle ale potřebujeme mít v každé třídě Logger s jinou kategorií (jménem). Ve WebBeans uděláte toto.
class LogFactory { @Produces Logger createLogger(InjectionPoint injectionPoint) { return Logger.getLogger(injectionPoint.getMember().getDeclaringClass().getName()); } }
InjectionPoint vám poskytne informace o tom, kam se vytvářená instance injektuje. Musím se přiznat, že jsem se pár hodin pokoušel udělat to samé ve Springu. Nakonec se mi za cenu neuvěřitelných prasáren podařilo, ale hezké to vůbec nebylo.
Dekorátor
Zajímavým nápadem jsou dekorátory. Je to něco jako interceptor, akorát typově kontrolovaný. Nejlépe to zas uvidíte na příkladu. V něm mám rozhraní Account, nějakou jako implementaci nebo dokonce implementace a já chci přidat logování operací větších než nějaká částka. Slušní lidé by si napsali normální wrapper. Pokud jste ale líní, tak můžete použít dekorátor a WebBeans se za vás postarají o ty nudné činnosti.
@Decorator public abstract class LargeTransactionDecorator implements Account { @Decorates Account account; @PersistenceContext EntityManager em; public void withdraw(BigDecimal amount) { account.withdraw(amount); if ( amount.compareTo(LARGE_AMOUNT)>0 ) { em.persist( new LoggedWithdrawl(amount) ); } } public void deposit(BigDecimal amount); account.deposit(amount); if ( amount.compareTo(LARGE_AMOUNT)>0 ) { em.persist( new LoggedDeposit(amount) ); } } }
Všimněte si prosím dvou věcí. První je, že je třída abstraktní, takže nemusím implementovat ty metody, které mě nezajímají. Druhá věc je injektnutí obalované instance pomocí anotace @Decorates. Pozor, dekorátor se nedá použít jako náhrada za AOP, jak jsem původně myslel. K tomu aby se to dalo použít, potřebujete rozhraní, které budete implementovat, takže třeba na transakce je to nepoužitelné. Ale nápad je to zajímavý.
Abych to shrnul. Pořád si myslím, že pro složitější konfiguraci je XML lepší. Mám pro to i jeden argument. V XML mohu mít víc instancí stejné třídy s různou konfigurací. To se může často hodit. U anotací platí vztah jedna třída jedna konfigurace. Nicméně to vypadá, že jsem se svým názorem v menšině, takže se s anotacemi musím asi smířit. Rozhodně se vyplatí si alespoň přečíst tu dokumentaci, něco se třeba naučíte. Čte se docela dobře a je i rozumně krátká. Z mého pohledu jsou WebBeans framework, který by teoreticky, za velmi nepravděpodobných podmínek, při vhodné konstelaci planet, až se mi to skoro nechce ani napsat, mohl na čas nabídnou funkce, které vám Spring nenabídne. Tím se oproti ostatním módním frameworkům docela liší.
Update (10.10.2009): Ještě link na zajímavý článek
Nevim jestli si nabyl stejneho dojmu jako ja, ale prislo mi, ze podle specifikace lze pouzit moznosti dependency injection WebBeans, tedy napriklad i pro SE projekty. Nikde jsem nevidel zadnou tvrdou vazbu na EE.
Asi to použít půjde i v SE. Jenom myslím, že to bude v EE specifikaci a taky je otázka kdo by v SE spravoval transakce a podobně. Ale dovedu si představit Spring based implementaci, je jen otázka k čemu by byla.
Me lezi v zaludku, ze tu neni standardizovany zpusob jak delat DI v SE. WebBeans presne tohle definuji, jenom meli oddelit core a tu nadstavbu pro napojeni na EE.
Aha, jestli jsem to správně pochopil, že by se o DI staral JVM? To mě nenapadlo a asi by se mi to ani nelíbilo. Cítím se tak nějak lépe, když se o podobné věci stará nějaký kontejner, který můžu v případě potřeby vyměnit nebo úplně zahodit.
A ani jinak necítím potřebu standardizace, JavaBean specifikace v tomto plně vyhovuje. Dovedu si představit, jak by lidi (mě nevyjímaje) řvali, že se jim Sun svým ošklivým standardem snaží zničit jejich oblíbený DI nástroj.
To jsme se asi nepochopili uplne. Ja jsem chtel taky samozrejme kontejner, ale nejaky uz v API SE Javy. Samozrejme s moznosti “pokud ti to nevyhovuje, pouzij neco jineho”.
Aha, to pak nastoluje otázku, proč vymýšlet nový kontejner, když už je jeden nadefinován v EE. Dovedu si pak představit, že by mohl existovat profil “jenom DI”, který by asi dělal to co si představuješ.
Já si pod pojmem Java SE představuji jenom JVM a standardní knihovny, pod pojmem Java EE všechno co je v SE plus nějaký kontejner a knihovny navíc.
Jakmile bychom zavedli do SE API na DI, tak by se samozřejmě začalo používat v knihovnách a pak už bychom byli donuceni ten kontejner používat vždy. Nebo by to dopadlo jako java.util.logging, kdy máme v SE standard, který nikdo nepoužívá právě proto, že nechce svoje uživatele nutit do jedné konkrétní implementace. Potíž je v tom, že se dopředu nedá odhadnout, jak by takový krok dopadl.
Pořád si myslím, že pro složitější konfiguraci je XML lepší. Mám pro to i jeden argument. V XML mohu mít víc instancí stejné třídy s různou konfigurací. To se může často hodit. U anotací platí vztah jedna třída jedna konfigurace.
Už se Lukáši těšíte na Spring Java Config? 🙂 tam už budete moci řídit počet instancí pregnantně.
>Nicméně to vypadá, že jsem se svým názorem v menšině,
Ale ešte nás je pár 🙂