Webové služby à la Spring

V poslední době docela často používal knihovnu Spring WS. Chtěl bych se s vámi podělit o zkušenosti, které jsem s tímto modulem udělal. Nejdřív bych měl ale upozornit, že nejsem expert na webové služby. O tom co je to port nebo binding mám jen mlhavou představu. Na druhou stranu jsem to nikdy vědět nepotřeboval. Nečekejte také žádný návod jak to používat. Původně jsem ho sice chtěl napsat, ale pak mi došlo, že bych jen kopíroval existující dokumentaci.
Než se ale pustíme do Spring-WS, začnu trochu zeširoka. Na webové služby se můžeme dívat ze dvou úhlů. Můžeme je vnímat jako trochu lepší vzdálené volání metod (RPC). Prostě označím metodu vhodně zvolenou anotací a nějaký framework se mi postará o to, aby tato metoda byla vzdáleně volatelná. Nijak zvlášť mě nezajímá to, jak bude komunikace probíhat. Prostě beru webové služby jako takovou trochu modernější Corbu nebo RMI.
Druhý přístup se na webové služby dívá z druhé strany. Bere je jako trochu vylepšený způsob výměny XML dokumentů. Při tomto přístupu je pro mě důležitý formát výměny dat, od něj se pak odvíjí způsob volání.
Samozřejmě oba přístupy nakonec skončí obdobně, liší se jen tím, co je pro mě důležitější. Spousta lidí se shoduje v tom, že druhý přístup dává větší smysl. Obvykle se dočtete, že při návrhu webové služby by se mělo začít u definice XML dokumentů, které budou sloužit pro výměnu dat (contract first). Dává to smysl. Definice dat je to, kde se budeme střetávat s konzumenty naší webové služby, XSD je to, co vidí a proti čemu programují. Nikoho nezajímá, jakou signaturu má naše metoda, konzumenty zajímá co všechno nám musí poslat a co my jim na oplátku pošleme jako odpověď.
Spring WS je postaven právě kolem contract-first přístupu. A musím přiznat, že je postaven docela dobře. Nečekejte super kvalitu, na kterou jste zvyklí od Springu. Spring WS je psán jinou partou lidí a občas člověk narazí na místa, která by šla udělat lépe. Nicméně i tak je to kvalitní knihovna a pokud jste zvyklí na Spring, konfigurace Spring WS vám přijde přímočará.
Než se vrhnu do popisu toho, jako co všechno Spring WS umí, zamysleme se nad tím, co si od takové knihovny představujeme. Já od ní chci několik věcí. Chci, abych se nemusel starat o mydlinky kolem SOAPu, chci se zabývat pouze zpracováním nákladu (payloadu), který mi v těch mýdlových bublinách přišel. Takže od WS knihovny chci, aby mi zpracovala SOAP, vybalila náklad a předala mi ho k zpracování. Protože nerad pracuji s XML, chci, aby mi pomohla s převodem z XML do objektů. U odpovědi chci aby udělala to samé, ale pozpátku. Pak by se také hodilo, aby mi pomohla s vygenerováním WSDL a pokud je to nutné s WS-Security. Když se na tyto požadavky podívám, zjistím, že už to všechno je vyřešeno. Zpracování SOAPu umí SAAJ, na serializaci XML máme taky hromadu frameworků. Stačí to všechno jenom pospojovat. A přesně to dělá Spring WS.
Co se mi na něm líbí je jednoduchá konfigurovatelnost. Nestalo se mi, že bych narazil na něco, co bych neuměl nakonfigurovat. Všechno je možné nastavit, snadno přeprogramovat a podobně.
Samozřejmostí je volba způsobu serializace z a do XML. Máte na výběr JAXB2, Castor, XStream, moje oblíbené XMLBeans a několik dalších. Vytvoření vlastního způsobu serializace je jen otázkou implementace dvou rozhraní.
Pokud potřebujete něco pokročilejšího, můžete použít interceptory. Ty fungují obdobně jako filtry u HTTP requestu, jsou ale spouštěny na úrovni SOAP dotazu a odpovědi. Spring WS obsahuje interceptor pro logování dotazů a odpovědí, který je docela užitečný. Navíc obsahuje interceptor, který umí spustit XSLT transformaci nad příchozím dotazem. To je super, pokud potřebujete upravovat formát dat. Například přidáte element do odpovědi. Ale v mezidobí, než všichni vaši klienti přejdou na novou verzi, musíte některým z nich vracet odpověď bez tohoto elementu. Není nic snazšího než napsat příslušnou XSLT šablonu, která ho z odpovědi vyhodí. To vám ušetří starosti s údržbou několika verzí té samé služby.
Interceptory navíc nabízejí skvělé místo pro úpravy jak dotazu tak odpovědi. Narazil jsem na následující problém, SAAJ negeneroval XML deklaraci na začátku XML dokumentu. Takové to <?xml version="1.0"?>. Bohužel jeden klient se toho dožadoval. Po půlhodině strávené výzkumem toho kde je chyba, jsem přišel na to, že z neznámého důvodu SAAJ implicitně XML deklaraci negeneruje. Všechno vyřešil trojřádkový interceptor, který nastavil správnou property tak, aby ji používal.
Co mě také potěšilo je generování WSDL. Člověk by si řekl, že je to samozřejmost. Nicméně například XFire měl s generováním WSDL z existujících XSD souborů pěkné problémy. Zamotal se v několikanásobných importech stejného XSD souboru a vracel mi nevalidní WSDL. To byl jeden z důvodů proč jsme přešli na Spring WS. (Druhý důvod byl, že už jeho vývoj skončil, teď se jmenuje CXF a konfigurace rozhodně není kompatibilní). Spring WS se stejným schématem neměl nejmenší problém, naopak potěšil takovou maličkostí jako je automatická změna URL webové služby ve WSDL podle toho, kde je nasazen.
Takže abych to shrnul, pokud děláte webové služby stylem contract-first a jste zvyklí na Spring, pak je Spring WS rozhodně dobrá volba. Jeho nevýhodou je, že vám nedá nic zadarmo. Chcete generovat WSDL? Musíte si to nakonfigurovat. Chcete validovat dotazy pomocí XSD? Musíte nastavit správný interceptor. Trochu nešikovné je, že pro integraci s frameworkem musíte implementovat jeho rozhraní nebo rozšířit jeho třídu. Nicméně pokud nemáte stovky různých webových služeb, tak vás pár obalovacích piditříd nezabije. Pokud je i malá obalovací třída pro vás moc, pak můžete použít anotace. Ty jsem ale nezkoušel, takže nemohu sloužit.
Mezi nevýhody Spring WS patří, že nepodporuje anotaci @WebMethod. Autoři tvrdí, že je to záměrně, že prý lidi nabádá ke škodlivému pohledu na webové služby jako na vzdálené volání metod. Nevím, jejich anotace @Endpoint mi nepřipadá o moc lepší. Ale i přes tyto nevýhody mi Spring WS připadá jako dobrá volba. Dává vám svobodu volby a to je podle mě docela užitečná věc.

7 Responses to “Webové služby à la Spring”

  1. lzap Says:

    Dívat se na WS jako na RPC službu podobnou CORBA nebo RMI je podle mého názoru nekorektní. WS nikdy nebudou RCP, protože za žádných okolností nedokáží uchovávat stav. Tj nelze nijak uchovávat instanci objektu na serveru (a nad tou volat poté metody), což je základní koncept CORBY či RMI. S WS sice lze dosáhnout jakési "míry stavovosti" pomocí HTTP sesesions, ale používá se to k úplně jiným účelům (např. load balancingu).

    Tím slovíčkem RPC se spíše označuje jen zabalení parametrů a výsledků volání. Nejedná se tedy o celkový koncept. WS nikdy nebyly RPC službou.

  2. lzap Says:

    ...nebudou RPC...

    v poslední době moc často píši RPC tak proto ten překlep 😉

  3. lzap Says:

    ...v poslední době moc často píši RCP...

    Rich Client Platform 😉

    Tak jsem se definitivně zamotal do zkratek...

  4. Martin Rubeš Says:

    Spring WS používám poměrně intenzivně na mém projektu, přes určité mouchy - nevalidně generovaná WSDL 🙂 Je to lepší, alespoň dle mých zkušeností, než třeba JAX-WS. Chystám se mé zkušenosti někam napsat, jenom si najít ten čas...

    Neexistence anotace @WebMethod považuji za obrovské plus, alespoň to nikdo nebude používat!

  5. Lukáš Křečan Says:

    Ahoj Martine, pamatuju si, jak si loni o @WebMethod básnil, jak je to úžasné. Rozhodně by mě zajímalo z jakých důvodů jsi změnil názor.

  6. Martin Rubeš Says:

    Contract First a stálost je tím důvodem. Po více než roce práce na velkých projektech masivně využívajích WS pro integraci jsem zjistil, že stálost rozhraní bez ohledu na použité technologie je velké plus. Tímto se snížil počet anotací, které se mi líbí na 2 (@Override a @SupressWarnings).

  7. Roman Musil Says:

    Martine: "nevalidně generovaná WSDL"? Zkus CXF jestli je 'to' i tam.
    Jinak dávám též hlas pro "Contract first". Tedy pokud se v době vývoje daná hromada XSD o velikosti cca 1-2MB nemění tak říkajíc "pod rukama", ale to je jiná pohádka (resp. peklo).