1概要
このチュートリアルでは、http://cxf.apache.org/[Apache CXF]フレームワークをSpring ** と一緒に構成および使用することに焦点を当てています - JavaまたはXML構成のいずれか。
Apache CXFに関するシリーズの第2弾です。 最初のもの は、JAX-WS標準APIの実装としてのCXFの基本に焦点を当てていました。
2 Mavenの依存関係
前のチュートリアルと同様に、以下の2つの依存関係を含める必要があります。
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxws</artifactId>
<version>3.1.6</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http</artifactId>
<version>3.1.6</version>
</dependency>
Apache CXFアーティファクトの最新バージョンについては、https://search.maven.org/classic/#search%7Cga%7C1%7Cg%3A%22org.apache.cxf%22[apache-cxf]を参照してください。
さらに、Springをサポートするには以下の依存関係が必要です。
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.3.1.RELEASE</version>
</dependency>
Spring成果物の最新版はhttps://search.maven.org/classic/#search%7Cga%7C1%7Cg%3A%22org.springframework%22[here]にあります。
最後に、従来の web.xml デプロイメント記述子の代わりにJava Servlet 3.0+ APIを使用してプログラムでアプリケーションを設定するので、以下のアーティファクトが必要になります。
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
</dependency>
こちら Servlet APIの最新バージョン
** 3サーバーサイドコンポーネント
Webサービスエンドポイントを公開するためにサーバー側に存在する必要があるコンポーネントを見てみましょう。
3.1. WebApplicationInitilizer インタフェース
WebApplicationInitializer インターフェースは、アプリケーション用に ServletContext インターフェースをプログラムで構成するために実装されています。クラスパスに存在する場合、その onStartup メソッドはサーブレットコンテナによって自動的に呼び出され、その後 ServletContext がインスタンス化され初期化されます。
以下は WebApplicationInitializer インターフェースを実装するためのクラスの定義方法です。
public class AppInitializer implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext container) {
//Method implementation
}
}
onStartup() メソッドは、以下に示すコードスニペットを使用して実装されます。
まず、Springアプリケーションコンテキストを作成し、設定メタデータを含むクラスを登録するように設定します。
AnnotationConfigWebApplicationContext context
= new AnnotationConfigWebApplicationContext();
context.register(ServiceConfiguration.class);
ServiceConfiguration クラスには、Bean定義を提供するために @ Configuration アノテーションが付けられています。このクラスについては次のサブセクションで説明します。
次のスニペットは、Springアプリケーションコンテキストをサーブレットコンテキストに追加する方法を示しています。
container.addListener(new ContextLoaderListener(context));
Apache CXFによって定義されている CXFServlet クラスは、着信要求を処理するために生成および登録されます。
ServletRegistration.Dynamic dispatcher
= container.addServlet("dispatcher", new CXFServlet());
アプリケーションコンテキストは、設定ファイルに定義されているSpring要素を読み込みます。この場合、サーブレットの名前は cxf なので、コンテキストはデフォルトで cxf-servlet.xml という名前のファイル内でこれらの要素を探します。
最後に、CXFサーブレットは相対URLにマッピングされています。
dispatcher.addMapping("/services");
3.2. 古き良き web.xml
あるいは、 WebApplicationInitilizer インタフェースではなく(やや昔ながらの)デプロイメント記述子を使用する場合は、対応する web.xml ファイルに次のサーブレット定義を含める必要があります。
<servlet>
<servlet-name>cxf</servlet-name>
<servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>cxf</servlet-name>
<url-pattern>/services/** </url-pattern>
</servlet-mapping>
3.3. ServiceConfiguration クラス
それでは、サービス構成を見てみましょう。まず、Webサービス・エンドポイントのBean定義を囲む基本的なスケルトンです。
@Configuration
public class ServiceConfiguration {
//Bean definitions
}
最初に必要なBeanは SpringBus です。これは、Apache CXFがSpring Frameworkと連携するための拡張機能を提供します。
@Bean
public SpringBus springBus() {
return new SpringBus();
}
EnpointImpl Beanも、 SpringBus BeanとWebサービス implementor を使用して作成する必要があります。このBeanは、指定されたHTTPアドレスでエンドポイントを公開するために使用されます。
@Bean
public Endpoint endpoint() {
EndpointImpl endpoint = new EndpointImpl(springBus(), new BaeldungImpl());
endpoint.publish("http://localhost:8080/services/baeldung");
return endpoint;
}
BaeldungImpl クラスは、Webサービスインタフェースを実装するために使用されます。
その定義は次の小節で述べる。
あるいは、サーバーエンドポイントをXML設定ファイルで宣言することもできます。具体的には、以下の cxf-servlet.xml ファイルは、サブセクション3.1で定義されている web.xml デプロイメント記述子と連携し、まったく同じエンドポイントを記述しています。
<jaxws:endpoint
id="baeldung"
implementor="com.baeldung.cxf.spring.BaeldungImpl"
address="http://localhost:8080/services/baeldung"/>
XML構成ファイルは、デプロイメント記述子に定義されているサーブレット名、つまり cxf に基づいて命名されています。
3.4. 型の定義
次に - これは前のサブセクションですでに述べた implementor の定義です:
@WebService(endpointInterface = "com.baeldung.cxf.spring.Baeldung")
public class BaeldungImpl implements Baeldung {
private int counter;
public String hello(String name) {
return "Hello " + name + "!";
}
public String register(Student student) {
counter++;
return student.getName() + " is registered student number " + counter;
}
}
このクラスはApache CXFが公開されているWSDLメタデータに含める Baeldung エンドポイントインタフェースの実装を提供します。
@WebService
public interface Baeldung {
String hello(String name);
String register(Student student);
}
エンドポイントインタフェースと implementor はどちらも Student クラスを使用します。このクラスは次のように定義されています。
public class Student {
private String name;
//constructors, getters and setters
}
4クライアントサイドBean
Spring Frameworkを利用するために、 @ Configuration アノテーション付きクラスでBeanを宣言します。
@Configuration
public class ClientConfiguration {
//Bean definitions
}
client という名前のBeanが定義されています。
@Bean(name = "client")
public Object generateProxy() {
return proxyFactoryBean().create();
}
client Beanは、 Baeldung Webサービスのプロキシを表します。 JAX-WSプロキシを作成するためのファクトリである JaxWsProxyFactoryBean Beanの create メソッドの呼び出しによって作成されます。
JaxWsProxyFactoryBean オブジェクトは、次のメソッドで作成および設定されています。
@Bean
public JaxWsProxyFactoryBean proxyFactoryBean() {
JaxWsProxyFactoryBean proxyFactory = new JaxWsProxyFactoryBean();
proxyFactory.setServiceClass(Baeldung.class);
proxyFactory.setAddress("http://localhost:8080/services/baeldung");
return proxyFactory;
}
ファクトリの serviceClass プロパティはWebサービスインタフェースを示し、 address プロパティはプロキシがリモート呼び出しを行うためのURLアドレスを示します。
また、クライアントサイドのSpring Beanの場合は、XML構成ファイルに戻ることがあります。次の要素は、上記でプログラムで設定したものと同じBeanを宣言しています。
<bean id="client" factory-bean="clientFactory" factory-method="create"/>
<bean id="clientFactory" class="org.apache.cxf.jaxws.JaxWsProxyFactoryBean">
<property name="serviceClass" value="com.baeldung.cxf.spring.Baeldung"/>
<property name="address" value="http://localhost:8080/services/baeldung"/>
</bean>
5テストケース
このセクションでは、Apache CXFによるSpringのサポートを説明するためのテストケースについて説明します。テストケースは StudentTest という名前のクラスで定義されています。
まず、前述の ServiceConfiguration 設定クラスからSpringアプリケーションコンテキストをロードし、それを context フィールドにキャッシュする必要があります。
private ApplicationContext context
= new AnnotationConfigApplicationContext(ClientConfiguration.class);
次に、サービスエンドポイントインタフェースのプロキシが宣言され、アプリケーションコンテキストからロードされます。
private Baeldung baeldungProxy = (Baeldung) context.getBean("client");
この Baeldung プロキシは、後述のテストケースで使用されます。
最初のテストケースでは、 hello メソッドがプロキシ上でローカルに呼び出されたときの応答が、エンドポイント implementor がリモートWebサービスから返すものとまったく同じであることを証明します。
@Test
public void whenUsingHelloMethod__thenCorrect() {
String response = baeldungProxy.hello("John Doe");
assertEquals("Hello John Doe!", response);
}
2番目のテストケースでは、生徒はプロキシ上の register メソッドをローカルに呼び出すことによってBaeldungコースに登録し、それがWebサービスを呼び出します。その後、そのリモートサービスは学生番号を計算し、それを発信者に返します。次のコードスニペットは、私たちが期待することを確認します。
@Test
public void whenUsingRegisterMethod__thenCorrect() {
Student student1 = new Student("Adam");
Student student2 = new Student("Eve");
String student1Response = baeldungProxy.register(student1);
String student2Response = baeldungProxy.register(student2);
assertEquals("Adam is registered student number 1", student1Response);
assertEquals("Eve is registered student number 2", student2Response);
}
6. 統合テスト
サーバー上のWebアプリケーションとしてデプロイするには、このチュートリアルのコードスニペットをまずWARファイルにパッケージ化する必要があります。これは、POMファイルで packaging プロパティを宣言することで実現できます。
<packaging>war</packaging>
パッケージング作業はMaven WARプラグインによって実装されています。
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>2.6</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
このプラグインはコンパイルされたソースコードをWARファイルにパッケージ化します。 Javaコードを使用してサーブレットコンテキストを設定するので、従来の web.xml デプロイメント記述子は存在する必要はありません。その結果、プラグインの実行時に失敗しないように、 failOnMissingWebXml プロパティを false に設定する必要があります。
https://search.maven.org/classic/#search%7Cga%7C1%7Cg%3A%22org.apache.maven.plugins%22%20AND%20a%3A%22maven-war-plugin%22 [このリンクはMaven WARプラグインの最新版のためのものです。
Webサービスの操作を説明するために、統合テストを作成します。このテストでは、まずWARファイルを生成して組み込みサーバーを起動し、次にクライアントにWebサービスを起動させ、後続の応答を確認して、サーバーを停止します。
以下のプラグインをMaven POMファイルに含める必要があります。詳細については、リンク:/apache-cxf-with-spring[この統合テストチュートリアル]をチェックしてください。
これがMaven Surefireプラグインです。
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.19.1</version>
<configuration>
<excludes>
<exclude>StudentTest.java</exclude>
</excludes>
</configuration>
</plugin>
このプラグインの最新バージョンはhttps://search.maven.org/classic/#search%7Cga%7C1%7Cg%3A%22org.apache.maven.plugins%22%20AND%20a%3A%22maven-にあります。 surefire-plugin%22[ここ]。
id が integration の profile セクションは、統合テストを容易にするために宣言されています。
<profiles>
<profile>
<id>integration</id>
<build>
<plugins>
...
</plugins>
</build>
</profile>
</profiles>
Maven Cargoプラグインは integration プロファイルに含まれています。
<plugin>
<groupId>org.codehaus.cargo</groupId>
<artifactId>cargo-maven2-plugin</artifactId>
<version>1.5.0</version>
<configuration>
<container>
<containerId>jetty9x</containerId>
<type>embedded</type>
</container>
<configuration>
<properties>
<cargo.hostname>localhost</cargo.hostname>
<cargo.servlet.port>8080</cargo.servlet.port>
</properties>
</configuration>
</configuration>
<executions>
<execution>
<id>start-server</id>
<phase>pre-integration-test</phase>
<goals>
<goal>start</goal>
</goals>
</execution>
<execution>
<id>stop-server</id>
<phase>post-integration-test</phase>
<goals>
<goal>stop</goal>
</goals>
</execution>
</executions>
</plugin>
cargo.hostname および cargo.servlet.port 構成プロパティーは、わかりやすくするために含まれているだけです。これらの設定プロパティはデフォルト値と同じであるため、アプリケーションに影響を与えずに除外することができます。このプラグインはサーバーを起動し、接続を待ち、最後にサーバーを停止してシステムリソースを解放します。
このリンク Maven Cargoプラグインの最新バージョンをチェックすることができます。
Maven Surefireプラグインは、 integration プロファイル内で再度宣言され、メインの build セクションの設定をオーバーライドし、前のセクションで説明したテストケースを実行します。
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.19.1</version>
<executions>
<execution>
<phase>integration-test</phase>
<goals>
<goal>test</goal>
</goals>
<configuration>
<excludes>
<exclude>none</exclude>
</excludes>
</configuration>
</execution>
</executions>
</plugin>
これで、プロセス全体をコマンド mvn -Pintegration clean install で実行できます。
7. 結論
このチュートリアルでは、Springに対するApache CXFのサポートについて説明しました。特に、Spring設定ファイルを使用してWebサービスを公開する方法と、別の設定ファイルで宣言されているApache CXFプロキシファクトリによって作成されたプロキシを介してクライアントがそのサービスと対話する方法を示しました。
これらすべての例とコードスニペットの実装はhttps://github.com/eugenp/tutorials/tree/master/apache-cxf/cxf-spring[リンクされたGitHubプロジェクト]にあります。