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

Brak komentarzy:

Prześlij komentarz