VÝVOJ PODNIKOVÝCH APLIKACÍ NA PLATFORMĚ JAVA - PŘEDNÁŠKA Zbyněk Šlajchrt http://java.vse.cz/4it447/HomePage Část 12.
CDI (WebBeans) Oficiální název Contexts And Dependency Injection Navrženo pro usnadnění provázání komponent z prezentační a aplikační vrstvy Tvůrci zamýšleli primárně použití v JSF CDI však není omezeno pouze na JSF Charakteristika Slabé vazby (loose coupling) "Stavově" orientované Typově bezpečné Flexibilní
CDI - Specifikace Specifikace JSR-299 Související specifikace Dependency Injection for Java, JSR-330 Managed Beans jako součást Java EE 6, JSR-316 Inspirace: Guice, Seam
Motivační příklad Nikdo není přihlášen: Uživatel je přihlášen:
Motivační příklad - schéma
Motivační příklad – JSP stránka V EL výrazech pracuji s instancí Login Nechci se starat o to, kde je tato instance uložena (scope) Nechce se mi ani deklarovat proměnnou login přes <jsp:useBean>
Motivační příklad - kontroler Nechci se obtěžovat s vytvářením instance Login Ani ukládáním instance do atributu odpovídajícího scope (setAttribute) Chci ji pouze používat, tj. volat její metody a nastavovat vlastnosti Nechť mi kontejner vstříkne do atributu odkaz na připravenou instanci
Motivační příklad – Managed bean Deklaruji, že bean Login je určen do HTTP session - @SessionScoped a že v EL výrazech se lze na něj odkazovat jménem "login". Zajistí @Named("login") Potřebuji pracovat s DB, ať mi tedy kontejner vstříkne EM. Jelikož v aplikaci může být více jednotek, upřesním ji vlastní anotací (tzv. kvalifikátorem) @Users
Motivační příklad: Prostředky Místo specifikace názvu JPA jednotky použiji kvalifikátor @Users Odstiňuje mne od detailů JPA konfigurace Mohu tak snadno použít různé JPA jednotky pro vývoj a produkci Prostředky používané v aplikaci deklaruji ve speciální komponentě @Produces indikuje, že prostředek je nabízen k použití všude, kde se vyžaduje EntityManager s kvalifikátorem @Users
Motivační příklad: Odeslání mailu Přihlášený uživatel může odesílat zprávy
Příklad: Upravené schéma
Příklad: Upravená JSP stránka
Příklad: Upravený kontroler Odesílání má na starosti bean Email Nechám si tedy vstříknout jeho instanci do atributu email a nestarám se o jeho životní cyklus
Příklad: Sdílení aktuálního uživatele Email bean potřebuje znát aktuálně přihlášeného uživatele, v jehož jménu odesílá zprávu. V Login beanu vytvořím produkční metodu getCurrentUser, která zveřejňuje aktuálního uživatele. Kvalifikátor @LoggedIn umožní propojení produkční a konzumentské strany.
Motivační příklad: Email bean Email bean odesílá mail ve jménu přihlášeného uživatele Nechám si vstříknout přihlášeného uživatele (kvalifikátor @LoggedIn) Pokud by nebyl nikdo přihlášen, tak se vyhazuje aplikační výjimka NotLoggedException a nikoliv NullPointerException, jak by se očekávalo. (Viz produkční metoda Login::getCurrentUser()) Potřebuji pracovat s prostředkem Java Mail Session. Zajistí kontejner. Ulehčím mu úkol upřesněním závislosti vlastním kvalifikátorem @MailSession
Příklad: Úprava beanu s prostředky Vytvořím nový atribut mailSession, do kterého kontejner nastaví odkaz na prostředek mail/myMailSession definovaný v JNDI (ENC) @Produces anotace zajistí jeho sdílení @MailSession kvalifikátor jej zpřístupní všem, kteří jej uvádí spolu s @Inject.
Souhrnný přehled vlastností CDI poskytuje dvě základní služby Kontexty Životní cyklus stavových komponent je svázán se s životním cyklem kontextu, do kterého patří. Dependency Injection Typově bezpečná injektáž komponent Možnost volby implementace injektované komponenty při nasazování aplikace Postaveno na anotacích (vlastních a vestavěných)
Další služby CDI Integrace s EL – možnost přímého použití komponent v JSP a JSF Schopnost dekorovat injektované komponenty Interceptory Událostmi řízené programování Konverzační scope jako doplněk k request, session a application scope SPI (Service Provider Interface) pro integraci dalších frameworků do prostředí Java EE 6
Slabé vazby Odděluje server a klienta pomocí rozhraní a tzv. kvalifikátorů. Serverová část se tak může měnit. Odděluje životní cykly jednotlivých komponent zařazením komponent do kontextů, jejich životní cyklus ke řízen automaticky Událostní programovací model odděluje konzumenty zpráv od jejich zdrojů Využití interceptorů napomáhá k vzájemnému odstínění komponent
Beans – redefinice pojmu Zdroj (továrna) kontextuálních objektů, jejich životní cyklus je řízen kontejnerem podle životního cyklu kontextu Bean nabízí jeden nebo více typů instancí S beanem jsou asociovány kvalifikátory S beanem je asociován scope (popisovač kontextu) Lze nastavit EL jméno Bean obsahuje implementaci
Bean, kontext, instance Context1 (of Scope1) IB1 creates B1 Scope1
Bean, kontext, instance Context1 (of Scope1) IB1 creates B1 creates Context2 (Scope1) Scope1 IB1
Typ beanu Typ instancí poskytovaných beanem Může být rozhraní, konkrétní i abstraktní třída generický typ pole primitivní typ
Managed Beans Bean, který je implementován Java třídou jsou i jiné způsoby implementace (rozšíření) Pravidla pro třídu managed beanu Není nestatická vnitřní třída Konkrétní třída, nebo anotovaná @Decorator Není anotovaná anotací EJB komponenty ani není deklarován jako EJB v ejb-jar.xml Má příslušný konstruktor bez parametrů s parametry a anotovaný @Inject
Beany jako injektovatelné objekty CDI umožňuje injektovat různorodější typy, než v původním Java EE 5 Umožňuje injektáž do objektů, které nejsou spravované kontejnerem Typy objektů, které mohou být injektovány (Skoro) všechny Java třídy Session Beans Java EE prostředky (JMS, Java Mail, JDBC atd.) PersistenceContext Produkční atributy a objekty vracené produkčními metodami Webové služby Vzdálená EJB rozhraní
Extra-jednoduchý managed bean patří do Dependent scope na bean se nelze odkazovat z EL
Kvalifikátory Použitím kvalifikátorů lze připravit více implementací jednoho typu Kvalifikátor je anotace definovaná jako @Target({METHOD, FIELD, PARAMETER, TYPE}) @Retention(RUNTIME) Touto anotací se anotuje třída managed beanu Používá se na straně konzumenta spolu s anotací @Inject
Kvalifikátory - příklad @Default je vestavěný kvalifikátor označující default implementaci.
Injektáž beanů Na straně konzumenta se požadavek na injektáž beanu vyjadřuje anotací @Inject Lze jí použít na atributu metodě konstruktoru Anotace @Inject se často doprovází kvalifikátory, které upřesňují požadavek na injektovaný bean
Injektáž - příklady
Scopes Životní cyklus beanu je určen tzv. scope Každý bean má přiřazen právě jeden scope Lze vytvářet vlastní Vestavěné scopes Scope Annotation Duration Request scope @RequestScoped Po dobu trvání HTTP dotazu. Session scope @SessionScoped Po dobu trvání HTTP session. Application scope @ApplicationScoped Po dobu běhu aplikace. Dependent scope @Dependent Životní cyklus odpovídá životnímu cyklu konzumujícího beanu. Conversation scope @ConversationScoped Po dobu trvání 'konverzace' v JSF aplikaci.
Pojmenování beanu pro EL Aby bylo možné se na bean odkazovat z EL, je zapotřebí jej pojmenovat Anotace @Named se umístí na třídu beanu Pokud se nezadá jeho hodnota, EL název beanu odpovídá názvu beanu s malým písmenem na začátku. Nestandardní název lze zadat v atributu value @Named("mailer")
Použití beanu v JSP Na bean se lze odkazovat z EL výrazu uvedením jeho jména ${login.currentUser.username} login je jméno beanu Login
Použití beanu ve facelet Typické použití je ve formuláři Gettery beanu se použijí pro výpis statického textu Settery se použijí k nastavení hodnot z formuláře Akce formuláře se nasměruje na jednu z metod beanu
Použití ve facelet: příklad @Model je tzv. stereotyp, neboli pojmenovaná skupina anotací. @Model obsahuje @RequestScoped a @Named
Produkční metody Produkční metody umožňují injektovat objekty, které nejsou beany mění se za běhu vyžadují speciální inicializaci Tyto metody se anotují @Produces spolu s upřesňujícími kvalifikátory
Produkční metody: příklad
Další features ... Interceptory Dekorátory Události Alternativy podobné interceptorům v EJB3 Dekorátory jako interceptory, ale obalují konkrétní třídu Události lze posílat notifikace o událostech posluchačům Alternativy konfigurace alternativních implementací beanů
Poznámky Aplikace musí vždy obsahovat beans.xml v adresáři WEB-INF
Zdroje Goncalves, Antonio; Beginning Java EE 6 Platform With GlassFish 3; APRESS http://java.sun.com/javaee/6/docs/tutorial JSR-299: Contexts and Dependency Injection for the Java EE platform