Autor wpisu: Splatch, dodany: 23.07.2008 08:27, tagi:
Od jakiegoś czasu w pracy do tworzenia usług sieciowych korzystam z Apache CXF. Jako że biblioteka jest stosunkowo nowa i nie najlepiej udokumentowana postanowiłem przedstawić na blogu jak wygląda proces tworzenia.
CXF jest połączeniem kilku bibliotek - YOKO, Celtixa oraz XFire. Każda z nich wcześniej realizowała pewien fragment obecnej funkcjonalności CXF - YOKO obsługuje Corbę a XFire usługi sieciowe. Obecne CXF jest gotowy do używania "produkcyjnego", ponieważ niedawno wyszedł z fazy inkubacji. :)
Architektura
CXF ma dosyć elastyczną budowę. Zgodnie z dokumentacją można wyróżnić najważniejsze składowe:
- Bus, jest trzonem architektury CXF w którym definiuje i konfiguruje się rozszerzenia.
- Messaging & Interceptors, zapewniają niskopoziomowy dostęp do komunikatów oraz warstwę na której jest oparta większość funkcjonalności.
- Front ends, frontendy są interfejsami programistycznymi do tworzenia usług (np. JAX-WS).
- Services, usługi zapewniają model wraz z opisem
- Bidings, element ten jest odpowiedzialny za obsługę konkretnego protokołu (SOAP, REST, Corba etc).
- Transports, warstwa abstrakcji ułatwiająca zmianę sposobu transportu do/z usług.
Markieting :)
CXF oferuje infrastrukturę konieczną do budowania usług, z najważniejszy zalet można wymienić:
- Wsparcie dla różnych protokołów.
- Obsługa standardów WS-*, tj. WS-Addressing, WS-Security, WS-ReliableMessaging, oraz WS-Policy.
- Obsługa wielu transportów.
- Dołączane data-bindingi (np JAXB, Aegis).
- Jasny podział front endów takich jak JAX-WS od najważniejszego kodu.
- Wysoka wydajność.
- Możliwość osadzania w różnych środowiskach.
Z dodatkowych zalet, mogę dodać - bardzo łatwą integrację ze Springiem.
Pierwsza usługa
Do budowania projektów będziemy używać Mavena. Implementowana usługa będzie oparta o frontend JAX-WS z ręcznie pisanym deskryptorem usługi (WSDL first). Jakkolwiek w bardzo prosty sposób można odwrócić kolejność i przy pomocy pluginu CXF do Mavena wygenerować deskryptor.
Struktura projektów będzie następująca:
- parent Rodzic projektu ze zdefiniowanymi wersjami bibliotek i raportami.
- contract Definicje używane zarówno przez klienta jak i serwer - WSDL oraz konfiguracja pluginu CXF.
- client Prosta biblioteka kliencka oparta o mechanizmy CXFa (JaxWSProxyFactoryBean).
- server Przykładowa implementacja usługi z bardzo prostym wykorzystaniem Springa.
- webapp Konfiguracja transporty CXF - w tym konkretnym przypadku servletu CXF.
Parent
Poniżej znajduje się deskryptor projektu, który jest używany do budowania całości.
<?xml version="1.0" encoding="UTF-8"?> <project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <!-- Informacja dla Mavena --> <modelVersion>4.0.0</modelVersion> <!-- Identyfikacja projektu --> <groupId>org.code-house.cxf</groupId> <artifactId>parent</artifactId> <name>Code House.Org - CXF</name> <version>1.0-SNAPSHOT</version> <packaging>pom</packaging> <description>Rodzic projektu, zawiera wszystkie moduly.</description> <!-- Składowe projektu --> <modules> <module>cxf-client</module> <module>cxf-contract</module> <module>cxf-server</module> <module>cxf-webapp</module> </modules> <!-- Definicje zmiennych dostępne również w modułach --> <properties> <code-house.cxf.version>2.1.1</code-house.cxf.version> <code-house.jaxb.version>2.1.3</code-house.jaxb.version> <code-house.spring.version>2.5.4</code-house.spring.version> </properties> <build> <plugins> <!-- Konfiguracja kompilatora --> <plugin> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.5</source> <target>1.5</target> </configuration> </plugin> </plugins> </build> <reporting> <!--Wycięte :) --> </reporting> <!-- Predefiniowane wersje bibliotek --> <dependencyManagement> <dependencies> <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-frontend-jaxws</artifactId> <version>${code-house.cxf.version}</version> </dependency> <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-transports-http</artifactId> <version>${code-house.cxf.version}</version> </dependency> <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-transports-http-jetty</artifactId> <version>${code-house.cxf.version}</version> </dependency> <dependency> <groupId>com.sun.xml.bind</groupId> <artifactId>jaxb-impl</artifactId> <version>${code-house.jaxb.version}</version> </dependency> <dependency> <groupId>javax.xml.bind</groupId> <artifactId>jaxb-api</artifactId> <version>2.1</version> </dependency> </dependencies> </dependencyManagement> </project>
Contract
Zgodnie z tym, co napisałem wcześniej - przyjąłem podejście, że WSDL jest pisany ręcznie, głównie dlatego że dla większych projektów można w prosty sposób narzucić jakąś organizację i podział plików, z których są następnie generowane źródła. Najistotniejsza wstawka, która powinna znaleźć się w pomie:
<!-- Generowanie kodu z deskryptora WSDL --> <plugin> <groupId>org.apache.cxf</groupId> <artifactId>cxf-codegen-plugin</artifactId> <executions> <execution> <phase>generate-sources</phase> <configuration> <sourceRoot>${basedir}/target/jaxws</sourceRoot> <wsdlOptions> <wsdlOption> <wsdl> ${basedir}/src/main/resources/maven.wsdl </wsdl> <extraargs> <extraarg>-quiet</extraarg> </extraargs> </wsdlOption> </wsdlOptions> </configuration> <goals> <goal>wsdl2java</goal> </goals> </execution> </executions> </plugin>
Po dodaniu tej wstawki do sekcji build/plugins możemy przejść do tworzenia deskryptora usługi. W moim przypadku przyjąłem następujący podział: