środa, 18 marca 2009

AbstractAdvisorAutoProxyCreator

Ostatnio dostałem zadanie dopisania paru rzeczy w projekcie wykorzystującym Spring Framework w wersji 1.2. Dodatkowo chciałem podbić wersję Springa do aktualnie wykorzystywanej w innych projektach, czyli do wersji 2.5.6. Parę razy już taką operację robiłem i zazwyczaj sprowadzało się to do wymiany jarów. Tym razem nie było inaczej i już po chwili aplikacja działała z nowym wersją Springa.
W projekcie należało dodać jedną prosty aspekt i chciałem wykorzystać do tego nową (dostępną już w wersji 2.0) składnie definiowania w xml konfiguracji Spring AOP, czyli korzystanie z przestrzeni nazw aop.
Po wprowadzeniu zmian i przetestowaniu, wyglądało jakby zadanie miało być skończone. Jednak zauważyłem dziwną rzecz: niektóre beany, które dotychczas nie były opakowywane przez żaden z aspektów zostały tym razem opakowane - zamiast POJO były to AOP proxy. Dotyczyło to tylko niektórych beanów, ale co ciekawsze zostały opakowane nie przez mój aspekt, ale przez inny istniejący zanim zacząłem wprowadzać zmiany.
Jak usunąłem wprowadzone przeze mnie zmiany wszystko zaczęło działać jak poprzednio i beany, które jeszcze przed chwilą widziałem jako Proxy teraz były zwykłymi POJO.
Wyglądało to jakby wprowadzenie nowego aspektu rozwaliło cała dotychczasową konfigurację Spring AOP.
Zacząłem przeglądać źródła Springa i po jakimś czasie znalazłem rozwiązanie. Problem wynikał z tego, że dotychczasowa konfiguracja Spring AOP opierała się na tworzeniu ProxyFactoryBean i podpinaniu do nich wszelkiego typu beanów będących Advisorami lub Interceptorami, a użycie nowej konfiguracji xml powoduję uaktywnienie się beana typu AspectJAwareAdvisorAutoProxyCreator, który to jest podklasą klasy AbstractAdvisorAutoProxyCreator. Klasa ta próbuje z każdego beana (tak nie do końca z każdego, ponieważ nie bierze pod uwagę pewnych klas beanów) stworzyć AOP proxy na podstawie zdefiniowanych w systemie advisorów. W wersji 1.2 aby otworzyć AOP proxy należało do beana typu ProxyFactoryBean podpiąć nazwe beana będący advisorem, to teraz sam Spring dla każdego beana wyszukuje liste advisorów, które do niego "można zastosować".
Jeśli lista ta nie będzie pusta, to tworzy dla danego beana AOP proxy i rejestruję w kontekście.

Zachowanie takie można zasymulować także w Springu 1.X poprzez dodanie do kontekstu beana typ DefaultAdvisorAutoProxyCreator.

Wielokrotnie słyszałem o tym aby nie mieszać różnych opcji konfigurowania tych samych rzeczy w Spring: choćby jednoczesnego definiowanie transakcji za pomocą annotacji i konfiguracji w xml. To samo dotyczy zresztą sposobu konfigurowania AOP, czego sam doświadczyłem.

piątek, 13 marca 2009

Spring WebServices on Websphere 6.1.0.x

Już jakiś czas temu stanąłem przed problemem uruchomienia Spring WebServices na Websphere 6.1.0.x. Chodziło o dołożenie do istniejącej aplikacji ear nowego modułu web (modułu webservices), który miał stanowić alternatywny interfejs dostępu do systemu. Oczywiście istniejący oraz nowy moduł web muszą delegować do współdzielonej warstwy service.
Sposób zdefiniowania konfiguracji Spring, w której to 2 contexty springowe modułów web aplikacji ear potrafią współdzielić wspólny context jest poza tematem tego wpisu.

Ze względu na problemy związane z "Jar Hell" próbując różnych ustawień i kombinacji JARów, przez długi czas przy starcie i/lub obsłudze komunikatów widywałem wyjątki: java.lang.VerifyError, java.lang.ClassCastException, java.lang.NoClassDefFoundException. W końcu udało mi się zestawić konfigurację w której działały enpointy typu PayloadRootAnnotationMethodEndpointMapping wraz z JAXB 2:
  • ze względu na to że mam 2 moduły web, których contexty mają delegować do współdzielonego contextu modułu service, jary spring framework są umiejscowione bezpośrednio pod ear, a moduły web odwołują się do nich za pomocą wpisów we własnych plikach Manifest.mf (sekcja Class-Path)
  • W katalogu WEB-INF/lib modułu web services wrzuciłem następujące jary (wszystkie skopiowane z katalogów dist oraz lib dystrybucji Spring WebServices):
    • activation-1.1.1.jar
    • jaxb-api-2.1.jar
    • jaxb-impl-2.1.5.jar
    • spring-oxm-1.5.2.jar
    • spring-oxm-tiger-1.5.2.jar
    • spring-webmvc.jar
    • spring-ws-core-1.5.2.jar
    • spring-ws-core-tiger-1.5.2.jar
    • spring-ws-support-1.5.2.jar
    • spring-xml-1.5.2.jar
    • stax-api-1.0.1.jar
    • XmlSchema-1.3.2.jar
  • zgodnie z FAQ Spring WebServices należy następnie "przykryć" wybrane jary z Websphere . Mamy następujące możliwości:
    • ustawić sposób ładowania klas na Parent-Last dla modułu webServices,
    • ustawić sposób ładowania klas na Parent-Last dla całej aplikacji,
    • zdefiniować własny classloader, który będzie nadrzędnym classloaderem dla classloadera aplikacji,
    Ze względu na to, że kilka razy miałem problemy ze względu na "maintaince" aplikacji, dla której zostały zmienione domyślne sposoby ładowania klas ("przypadkowe" ładowanie klas z servlet-api.jar z katalogu WEB-INF/lib), zdecydowałem się na zdefiniowanie własnego classloadera.
  • Definiowanie własnego classloadera jest szczegółowo opisane w dokumentacji Websphere i polega na wykonaniu następującyh kroków:
    • zdefiniowaniu shared-library, w której znajdować się będą jary zawierające klasy, które to mają być ładowane przez tworzony classloader. Nasza nowo tworzona shared-library musi zawierać następujące jary(wszystkie skopiowane z katalogu lib dystrybucji Spring WebServices):
      • wsdl4j-1.6.1.jar
      • xalan-2.7.0.jar
      • xercesImpl-2.8.1.jar
    • zdefiniowaniu nowego classloadera na poziomie serwera i przypięciu do niego utworzonej w poprzednim punkcie shared-library. Ważne jest, aby sposób ładowania klas dla tego classloader był ustawiony na Parent-Last (czyli Application-First).
  • W końcu w naszej aplikacji musimy zdefiniować bean, który będzie definiował specyficzną dla środowiska uruchomieniowego fabrykę do tworzenia obiektów SOAPMEssage:





W takiej konfiguracji korzystam z dobrodziejstw Spring WebSevices. Ze względu na to, że WAS 6.1.0.x implementuje tylko SAAJ 1.2, moje endpointy obsługują komunikaty SOAP w wersji 1.1

wtorek, 10 marca 2009

Spring 3.0 Talk with Arjen Poutsma

Wczoraj wybrałem się do Warszawy na prezentacje Arjena Poutsmy na temat Spring 3.0.
Prezentacje odbyła się przy współpracy SpringSource i Warszawa JUG. Oficjalnie odbywały się zapisy przez Internet na prezentacje, była lista uczestników i lista rezerwowa, do tych pierwszych przychodził mail z biletem, który trzeba było wydrukować, aby wejść do środka.
Wszystko okazało się niezłą ściemą, ale i tak ludków przybyło całkiem sporo.
Prezentacja odbywała się w tej samej sali jak podczas WarsJava, ale publika tym razem o wiele bardziej dopisała, i dla kilku osób zabrakło krzeseł.

Zgodnie z zapowiedziami Arjen Poutsma miał w godzinach 17-20 zaprezentować nam głównie co nowego jest przygotowywane w Spring 3.0. Po przeczytaniu abstractu prezentacji zapowiadało się naprawdę ciekawie:
  • New features in Spring 3.0
  • Performance tuning Spring 3.0
  • An overview of Spring Projects
  • Enterprise capabilities for Spring
Zaczęliśmy z małym opóźnieniem, ale przynajmniej pizza przyjechała na czas :) i podczas gdy publikuje zajadała się pierwszą z 2 zaplanowanych dostaw, speakera jeszcze nie było.
Pojawił się z około 15 minutowy opóźnieniem, po rozłożeniu maca i posileniu się pizzą mogliśmy zaczynać.
Już na początku, okazało się, że Arjen Poutsma ma przygotowane 2 prezentację i zacznie od tej bardziej ogólnej: p.t „7 reasons to use Spring”. Zaczęło się od nieśmiertelnej maksymy autorstwa Alana Kaya „Simple things should be simple, complex things should be possible” i później kolejno zostały omawiane poszczególne powody, dla których warto wybrać Springa:
  1. DI - Nastąpiła krótka opowieść o POJO, jako o obiektach javowych niezależnych od środowiska, - czyli takich które nie posiadają żadnych „environment specific imports”i zależności od żadnych lookup methods. Dalej krótka opowieść czemu POJO są takie fajne i czemu EJB w wersji 2 nie było fajne. Potem był mały przykładzik, w którym to można było zobaczy w akcji mechanizm DI operujący na POJO, gdy konfiguracja została opisana raz to w XML, raz za pomocą annotacji. Mnie bardziej zaciekawił slajd p.t „ Why not use Java EE DI ?”, w którym to zostało podkreślone, że w JAVA EE „wstrzykiwanie zależności” polega na „wstrzykiwaniu” obiektów z JNDI, czyli takie „wstrzykiwanie” nie będzie działać w środowisku JUNIT.
  2. JdbcTemplate –zaczęło się od krótkiego przypomnienia, że do pewnych zadań (batch operations, stored procedures, sophisticated/analytic queries) lepiej jest cały czas korzystać z czystego JDBC niż całej maści różnych ORM. Następnie typowy przykład ile się trzeba namęczyć, jeśli chodzi o ilośćniezbędnych linii kodu oraz o odpowiednie zamykanie zasobów, aby korzystać z JDBC API. Używanie JdbcTemplate w takich sytuacjach nie tylko pozwoli nam drastycznie zmniejszyć ilość kodu, która musielibyśmy napisać, ale też zajmie się zamykaniem zasobów: PreparedStatement, ResultSet, Connection. Ze względu na to, że każda operacja wyciągnięcia danych za pomocą SQL sprowadza się jedynie do podania zapytania, jego parametrów oraz ewentualnego „obrobienia” ResultSeta reszta to „boiler plate code”, którym lepiej się nie zajmować i zostawić go JdbcTemplate.
  3. Exception hierarchy – równie powiązane z dostępem do BD, stworzona w Springu hierarchia wyjątków, która umożliwia w spójny sposób radzenie sobie z wszelkiego rodzajami błędami związanymi z dostępem do bazy danych. Kod błędu ze sterownika JDBC jest mapowany w zależności od używanej bazy danych na wyjątek określonego typu, który możemy złapać i obsłużyć jeśli będziemy mieć taką potrzebę, np. złapać DeadlockLoserDataAccessException aby ponowić operację.
  4. AOP – nadmienione zostały podstawowe pojęcia: pointcut, jointpoint, aspect, cross cutting concern, wraz z typowymi przykładami wykorzystania AOP: transakcji, logowanie, bezpieczeństwo, cachowanie. AOP przede wszystkim ma służyć aby poradzić sobie z 2 problemami:
    • Code tangling – gdy klasa/metoda nie zajmuję się wyłącznie logiką dla której została stworzona, ale dodatkowo zawierają kod związany z innymi funkcjonalnościami: sprawdzanie warunków bezpieczeństwa, obsługa logowania/transakcji.
    • Code scattering – w przypadku gdy kod (dotyczy to choćby pojedynczego wywołania) związany z daną sprawą(aspektem) jest rozsiany pomiędzy wiele klas, które w swoich założeniach powinny zajmować się jedynie swoją funkcjonalnością.
    Potem nastąpił sztandarowy przykładzik logowania przy wykorzystaniu Spring AOP plus krótkie wyjaśnienie czym Spring AOP różni się od AspectJ.
  5. Transactional - czyli możliwość deklaratywnego definiowania transakcji.
  6. Scripting Languages - możliwość definiowanie beanów w językach skryptowych uruchamianych na JVM: Groovy, BeanShell, JRuby. Ma to umożliwiać tworzenie rozwiązań w stylu "mix 'n match", w których to backend systemu będzie napisany w Javie a fronetend w języku skryptowym, a wszystko będzie spięte przez Springa.
  7. OSGI - jako technologia, która pozwala poradzic sobie z 2 problemami w świecie Javy: "JAR hell" oraz "module encapsulation". Dodatkowo wymienione zostały 2 produkty SpringSource, związane z OSGI: Spring Dynamic Modules oraz Spring DM Server. Arjen pokazał w jaki łatwy sposób w Springu opakować istniejącego beana aby stał się usługą OSGI, bez potrzeby uzależniania naszego kodu od inwazyjnego API OSGI
Na tym skończyła się pierwsza prezentacja, nastąpiła 15 minutowa przerwa, po której Arejn rozpoczął omawianie "RESTFul Web Application in Spring 3.0".
Nie mogło się obejść od krótkiego omówienia czym jest REST i co w nim chodzi. Były to bardziej pobieżne informację do tych, które umieściłem tutaj. Dodatkowo Arjen uczulił szczególnie na nadmierne/niewłaściwe wykorzystywanie parametrów zapytań, które w swoim założeniu powinny być "parametrami wejściowymi algorytmów", np. http://www.google.pl/search?q=java
Często zostają jednak użyte do innych celów (przemycanie faktycznej metody do wykonania), poza tym mogą być ignorowane przez proxy. 2 sprawą, która powinna wzbudzić naszą czujność są czasowniki w URL, ponieważ URL dotyczy zasobu/bytu który jest "rzeczą" a nie czynnością.
Pozostała cześć prezentacji okazała się kopią tego co znajduję się na blogu Arjena.

Podsumowując, prezentacja była całkiem niezła,(zresztą jak wszystkie te przeprowadzane przez konsultantów SpringSource), ale skierowana dla osób, które nie znają Springa lub znają go bardzo pobieżnie. Było zbyt mało informacji na temat Spring 3.0 (który tak na marginesie oprócz REST, nowego EL oraz odcięcia się od Javy 1.4 nie wnosi zbyt wiele nowego), a zgodnie z abstractem prezentacji to właśnie miało być tematem przewodnim . Dodatkowo w wielu miejscach argumenty przedstawiane przez Arjena, które miały świadczyć o wyższości Springa nad innymi technologiami były trochę "out-of-date".