VÝVOJ PODNIKOVÝCH APLIKACÍ NA PLATFORMĚ JAVA - PŘEDNÁŠKA Zbyněk Šlajchrt http://java.vse.cz/4it447/HomePage Část 5.
Interceptory Zavádí prvky aspektově orientovaného programování Použití Cross-cutting concerns operace prováděné napříč aplikací obvykle se nevážou na jednu třídu, ale na skupinu tříd, resp. metod Použití logování profilování transakce security kontrola vstupních parametrů volání metody
Interceptory - dělení Around-Invoke Life-cycle obalují volání metod mohou existovat jako samostatné komponenty lze je aplikovat napříč aplikací pomocí anotací nebo deklarací v ejb-jar.xml interceptor vázaný na EJB bean definován jako speciální metoda ve třídě EJB beanu je aktivován pouze na business metodách třídy EJB beanu Life-cycle aktivují se při událostech v životním cyklu EJB beanů
Samostatné vs. vázané interceptory Samostatné interceptory I1 I2 I2 BeanA BeanB Vázaný interceptor BeanC
Příklad: Interceptor vázaný na EJB Metoda logMethod obaluje volání všech business metod na ShoppingBean-u
Pravidla pro metodu interceptoru Anotovaná @javax.interceptor.AroundInvoke Povinná hlavička Object <METHOD>(InvocationContext ic) throws Exception může být public, private, protected i package-private nesmí být static nebo final Metoda smí vyhazovat kontrolovanou výjimku
Interceptor - sekvenční diagram
InvocationContext Umožňuje interceptoru řídit chování řetězu volání Na metodu lze nasadit více interceptorů Metody v InvocationContext proceed – způsobí volání dalšího interceptoru nebo vlastní metody na beanu getMethod – volaná metoda (java.lang.reflect.Method) getParameters – parametry volání setParameters – nastavuje (mění) parametry volání getTarget – instance beanu, na kterém se metoda volá getContextData – slouží k předávání hodnot mezi interceptory v rámci jednoho řetězu volání
Samostatný interceptor Lze nasadit na metody EJB beanů napříč aplikací Implementace v samostatné třídě Nasazení pomocí anotací metod, které se mají obalit interceptorem deklarativně v ejb-jar.xml Možnost nasadit na vybrané metody vybrané EJB beany paušálně na všechny metody všech beanů
Samostatný interceptor
Aplikace interceptoru na třídu Interceptor lze explicitně nasadit na třídu EJB beanu @Interceptors(<SEZNAM_TŘÍD_INTERCEPTORŮ>) Všechny business metody takového beanu budou obaleny interceptorem pomocí anotace @ExcludeClassInterceptors lze potlačit nasazení interceptorů třídy na metodě
Aplikace interceptoru na metodu Interceptor lze explicitně nasadit na metodu znovu anotací @Interceptors
Aplikace interceptorů v ejb-jar.xml
Interceptory - default binding Často je užitečné nasadit interceptor na všechny metody všech EJB beanů od verze EJB 3.1 Konfigurace v ejb-jar.xml
Potlačení interceptorů anotacemi Problém: Interceptory třídy a defaultní interceptory se mohou vázat na metody či EJB, u kterých si to nepřejeme Možnost explicitně vyloučit pomocí anotací na úrovni metod i tříd
Potlačení interceptorů v ejb-jar.xml Pomocí tagů <exclude-class-interceptors> a <exclude- default-interceptors>
Injektáž závislostí do interceptoru Plná podpora DI v interceptorech Interceptory sdílí jmenný kontext (ENC) s EJB, jehož metody obalují
Interceptory životního cyklu Odchytávají události v životním cyklu EJB Připomenutí – anotace metod na EJB volané kontejnerem při událostech v životním cyklu @PostConstruct, @PreDestroy, @PrePassivate, @PostPassivate Interceptory používají stejné anotace Liší se hlavička metody @<annotace> void <metoda>(InvocationContext ic) narozdíl od AroundInvoke nemůže vyhazovat kontrolované výjimky a musí vždy volat ic.proceed
Interceptor životního cyklu - příklad
Životní cyklus interceptoru Sdílí životní cyklus s EJB, na který je navázán je vytvářen spolu s EJB je odstraněn společně s EJB Pokud je EJB stavový, týká se interceptoru také pasivace a aktivace Sdílejí také omezení Např.: do interceptoru nelze injektovat odkaz na stavový EJB, pokud EJB, na který je interceptor navázán, není stavový.
Zpracování výjimek v AroundInvoke Vyhozením výjimky před voláním proceed() lze přerušit volání metody kontrola hodnot vstupních parametrů Lze odchytávat výjimky z proceed() a vyhazovat odlišné nebo je potlačovat Např. abstrakce JDBC výjimek kódy ve výjimkách závisí na výrobci pro různé databáze různý interceptor vyhazující abstrahované výjimky V @AroundInvoke metodě lze proceed() volat vícekrát, např. v catch bloku zopakovat volání
Timer - časovač Java EE aplikace často potřebují spouštět úlohy v naplánovaných okamžicích. Např. výstupní sestavy v pravidelných intervalech EJB 2.1 zavedlo službu Timer funkcionalita byla velmi omezená Timer v EJB 3.1 inspirace cron, Quartz služba kontejneru pro registraci a spouštění naplánovaných úloh perzistentní charakter (by default) plán spouštění přetrvává mezi restarty serveru
Automatická nebo programová Timer - schéma Automatická nebo programová registrace Timer Service Session Bean Notifikace beanu po vypršení časovače EJB vytváří časovač a registruje se v něm k notifikaci Kontejner spravuje všechny časovače a zajišťuje vyvolávání notifikací ve specifikovaných okamžicích Perzistentní charakter Stavové beany se nemohou registrovat k notifikacím.
Automatické vytváření časovače Časovače mohou být vytvářeny automaticky kontejnerem v čase umístění aplikace (deploy) Pro každou metodu v EJB anotovanou @Schedule nebo @Schedules je vytvořen časovač Možno deklarovat v ejb-jar.xml
Programové vyváření časovače Prostřednictvím rozhraní javax.ejb.TimerService Lze jej získat injektáží z kontextu EJBContext, metoda getTimerService() JNDI lookup
Programové vytváření časovače Injektovaná služba časovače si "pamatuje" bean, do kterého byla injektována. To umožní asociovat bean a jím vytvářené instance časovačů. Hondota true znamená, že časovač bude perzistentní. Třída cz.vse.javaee.OrderServiceBean
Metody TimerService getTimers createTimer createSingleActionTimer Vrací všechny časovače asociované s beanem createTimer Vytváří časovač na základě datumu, intervalu nebo trvání createSingleActionTimer Vytvoří časovač, který je po vypršení odstraněn createIntervalTimer Vytvoří časovač na základě intervalu mezi vypršeními createCalendarTimer Vytvoří časovač použitím kalendářového výrazu
Příklady kalendářových výrazů Třída ScheduleExpression Vytvoření časovače z kalendářového výrazu
Metody časovače cancel getInfo getNextTimeout getTimeRemaining zruší časovač a všechna asociovaná vypršení getInfo vrací informace asociované s časovačem při jeho vytváření getNextTimeout vrací okamžik příštího vypršení časovače getTimeRemaining vrací počet milisekund, které schází k další k expiraci getHandle vrací serializovatelné memento k časovači vhodné pro předávání jako argument pro vzdálená volání
Zrušení časovače Časovač lze zrušit voláním metody cancel()
Utilita cron UNIXová utilita pro plánování skriptů Umožňuje plánovat pomocí kalendářových výrazů Kalendářový výraz je šablona, podle které lze určit, kdy má být skript spuštěn lze zadat minutu, hodinu, den v týdnu, den v měsíci a měsíc Např. lze naplánovat, aby byl skript spuštěn každý první den v měsíci ve 12:30.
Formát cron výrazu Pět polí oddělených mezerou nebo tabulátorem Minuta Hodina DenVMěsíci Měsíc DenVTýdnu (0-58) (0-23) (1-31) (1-12) (0-6, neděle=0) Jako hodnotu lze použít *, která označuje, že všechny hodnoty jsou platné Příklady 20 * * * * - 20 minut po každé hodině 5 22 * * * - Každý den v 22:05 0 8 1 * * - První den v měsíci v 8:00 0 8 4 7 * - 4. července v 8:00 0 8-17 * * 1,3,5 – Každou hodinu od 8-17:00 v po, st a pá
Kalendářové výrazy v Java EE 6 Inspirace cron Rozšiřuje o možnost zadávat sekundy, rok a časové pásmo Kromě specifických hodnot, výčtů a rozsahů lze zadávat i přírůstky minute="*/15" hour="*" – každých 5 minut second="30/10" – každých 10 vteřin od 30. vteřiny
Atributy kalendářových výrazů Popis Možné hodnoty Default hodnota second Sekunda(y) [0..59] minute Minuta(y) hour Hodina(y) [0..23] dayOfMonth Den (dny) v měsíci [1..31], {"1st", "2nd", "3d", ...}, "Last", -x (znamená x dní před posledním dnem) * month Měsíc(e) [1..12], {"Jan", ...} dayOfWeek Den (dny) v týdnu [0..7] (0 a 7 je neděle), {"Sun", ...} year Rok YYYY timezone Časové pásmo Viz zoneinfo db (tz)
Enterprise Naming Context (ENC) EJB komponenta "nežije" ve vakuu Spojení s okolním světem zprostředkovává kontext vytvářený kontejnerem Každá komponenta má vlastní kontext ušitý na míru Umožňuje aplikaci vyhledávat distribuované prostředky, služby a EJB komponenty
Typy prostředků v ENC Odkazy na libovolné EJB rozhraní Odkaz na webové služby JMS destinace (fronty a topiky) JMS továrny připojení JDBC datové zdroje Java Connector API (JCA) prostředky Primitivní hodnoty Java EE služby UserTransaction, TimerService, org.omg.CORBA.ORG
ENC – JNDI Lookup JNDI = Java Naming And Directory Interface Kontext pro BeanA BeanA checkId=true mail/mailSession=<reference> ejb/BeanB=<reference> jdbc/BankDataSource=<reference> jms/BankQueue=<reference> context.lookup("java:comp/env/ejb/BeanB")
ENC – Dependency Injection Provádí kontejner při inicializaci EJB komponenty Nadstavba na vyhledáváním (lookup) Kontext pro BeanA BeanA checkId=true mail/mailSession=<reference> ejb/BeanB=<reference> jdbc/BankDataSource=<reference> jms/BankQueue=<reference> @Resource(name="jms/BankQueue") private Queue bankQueue
ENC – Dependency Injection Anotace atributů nebo setterů @Resource Různé prostředky, např. mail session, JMS prostředky, JDBC datové zdroje, služba časovače, SessionContext @EJB Stavové a bezstavové beany @PersistenceContext JPA entity managerem (pro práci s databází) @WebServiceRef Odkaz na rozhraní webové služby
ENC – Dependency Injection
Kontext pro ShoppingBean ENC – Inicializace <session> // konfigurace // ShoppingBean </session> Kontext pro ShoppingBean Shopping Bean ejb/OrderService=<reference> jdbc/myDS=<reference> ejb-jar.xml anotace
Konfigurace ENC EJB beanu XML deklaracemi Každá reference na službu, prostředek či EJB deklarovaná v XML deskriptoru vede k registraci v ENC Jméno pro lookup v beanu ATMServiceBean (s prefixem java:comp/env) ejb-jar.xml
Konfigurace anotacemi Alternativa k deklaraci v XML deskriptorech @EJB anotace na třídě deklaruje odkaz na EJB v ENC Ekvivalentní zápis v XML deskriptoru (zde web.xml)
ENC – Kombinace přístupů
Odkazování na prostředky JNDI – adresářová služba (často nad LDAP či AD) MyApp1 Kontext pro ShoppingBean Shopping Bean ejb/OrderService=<reference> jdbc/myDS=<reference> MyApp1/ejb/OrderService=... MyApp1/jdbc/myDS=... MyApp2/jms/LogQueue=... MyApp2/jdbc/someDS=... Na úrovni aplikačního serveru Některé záznamy lze (je třeba) konfigurovat, jiné se instalují automaticky po nahrání aplikace.
Vyhledávání v lokálním kontextu "java:comp/env" Prefix pro vyhledávání objektů v lokálním ENC komponenty java:comp/env/ejb/Shopping Kód v servletu či EJB: Deklarace odkazu na EJB ve web.xml nebo ejb-jar.xml v sekci <session>:
ENC a princip oddělení zájmů Deployer by měl být schopen přizpůsobit aplikaci bez zásahu do kódu aplikace Vývojář by měl v ideálním případě vyvíjet aplikaci bez znalosti cílového prostředí
Sdílení položek v ENC WAR EJB-JAR ve WAR modulu je pouze jediný ENC kontext všechny komponenty zabalené ve WARu (servlety, tagy, posluchači, JSP, EJB) jej sdílí EJB-JAR ve EJB modulu má každý bean vlastní ENC kontext interceptory sdílí ENC svázaného EJB beanu
Globální JNDI jméno Vzdálená klientská aplikace vyhledává session beany v JNDI Musí sestavit globální jméno – absolutní cestu Do verze Java EE 6 nebylo standardizováno Java EE 6 – Syntaxe pro globální jméno java:global[/<app>]/<module>/<bean>[!<interface >] java:global/prednaska5-app/ejb/ShoppingBean! cz.vse.javaee.ShoppingRemote
Globální jméno - příklad