Apache CXF+SpringによるWebサービス開発(JAX-WS編)


Apache CXFとSpring Frameworkを用いたJAX-WS仕様に準拠したWebサービス開発について紹介します。

なお、ここで紹介するソースコード例は、筆者環境の都合上、次の環境を前提とします。

  • Java SE6
  • Apache CXF 2.3.3
  • Spring Framework 3.0.5
  • Apache maven 3.0(jetty plugin等を利用)

また、JAX-WS仕様やApache CXFについては、wikiにまとめてありますので、詳細についてはそちらを参照下さい。

Webサービス(プロバイダ)を作成する

それでは、早速Webサービスを作成します。
JAX-WS仕様に基づき作成するため、基本的なポイントは大体同じですが、Aapche CXFとSpringで開発を進める場合の手順を説明します。

  1. サービスエンドポイントインタフェース(SEI)を作成する
  2. SEIの実装クラス(サービスクラス)を作成する
  3. CXFのJAX-WS フロントエンドとサービスクラスを Spring Bean として定義する
  4. CXFとSpring を統合するための web.xml を作成する

サービスエンドポイントインタフェース(SEI)を作成する

Webサービスとして公開するサービスの仕様を定義します。
サービスの仕様は、複数の整数を受け取り、その整数の集計をする簡単なサービスとします。

src/main/java/jp/opensquare/sandbox/cxf/jaxws/provider/Calculate.java

package jp.opensquare.sandbox.cxf.jaxws.provider;

import java.util.List;

import javax.jws.WebMethod;
import javax.jws.WebService;

@WebService
public interface Calculate {
	@WebMethod
	int sum(List<Integer> values);

}


JAX-WSのアノテーションを付与するところがポイントです。

SEIの実装クラス(サービスクラス)を作成する

SEIとして定義したインタフェースに沿って実装します。

src/main/java/jp/opensquare/sandbox/cxf/jaxws/provider/CalculateImpl.java

package jp.opensquare.sandbox.cxf.jaxws.provider;

import java.util.List;

import javax.jws.WebMethod;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.jws.soap.SOAPBinding.ParameterStyle;
import javax.jws.soap.SOAPBinding.Style;
import javax.jws.soap.SOAPBinding.Use;

@WebService(
		endpointInterface="jp.opensquare.sandbox.cxf.jaxws.provider.Calculate",
		serviceName="CalculateService",
		portName="CalculatePort",
		targetNamespace="http://provider.jaxws.cxf.sandbox.opensquare.jp/")
@SOAPBinding(
		style=Style.DOCUMENT,
		use=Use.LITERAL,		
		parameterStyle=ParameterStyle.BARE)
public class CalculateImpl implements Calculate {
	@Override
	@WebMethod
	public int sum(List<Integer> values) {
		int sum = 0;
		for(int value : values) {
			sum += value;
		}
		return sum;
	}
}


@WebServiceアノテーションのendpointInterface属性にSEIのFQCNを指定します。

ここまででわかることは、CXFだからといって特に特別な実装になっていないことがわかります。

CXFのJAX-WS フロントエンドとサービスクラスを Spring Bean として定義する

ここからは、Webサービスの配備に関連する設定の説明に移ります。CXFで用意されているフロントエンドを使用してWebサービスを定義します。見てわかるようにフロントエンドには、サービスの実装クラスのFQCNとサービスをマッピングするアドレスを指定するだけです。

src/main/resources/provider-beans.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws"
	xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">

	<import resource="classpath:META-INF/cxf/cxf.xml" />
	<import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" />

	<jaxws:endpoint id="calculate"
		implementor="jp.opensquare.sandbox.cxf.jaxws.provider.CalculateImpl"
		address="/CalculateService" />
</beans>


JAX-WSのみを利用した開発では、Webサービスを配備するJavaEEアプリケーションサーバによって配備手順に多少の違いはありますが、CXFとSpringの組み合わせでは配備手順に違いはありません。

CXFとSpring を統合するための web.xml を作成する

web.xmlには、次のようにSpringのBean定義のロード定義とCXFServletの定義を行うだけです。

src/main/webapp/WEB-INF/web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app>
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>classpath:/provider-beans.xml</param-value>
	</context-param>

	<listener>
		<listener-class>
			org.springframework.web.context.ContextLoaderListener
		</listener-class>
	</listener>

	<servlet>
		<servlet-name>CXFServlet</servlet-name>
		<display-name>CXF Servlet</display-name>
		<servlet-class>
			org.apache.cxf.transport.servlet.CXFServlet
		</servlet-class>
		<load-on-startup>1</load-on-startup>
	</servlet>

	<servlet-mapping>
		<servlet-name>CXFServlet</servlet-name>
		<url-pattern>/*</url-pattern>
	</servlet-mapping>
</web-app>


以上で、サービス開発は完了です。

リクエスタの開発

CXFが本当にすばらしいと感じるのは、フロントエンドに触れた時です。リクエスタ開発は、通常であればwsimortコマンドでWSDLからプロキシを生成し、そのプロキシを用いてサービルコールを行います。しかし、プロキシを生成すると「JAX-WS仕様は、イケテナイ」で紹介している微妙な問題が生じます。
CXFのフロントエンドは、動的にプロキシコードを生成する機能を提供します。そのため、wsimportを行わなくても簡単にサービスコールができます。

CXFのJAX-WS フロントエンドを使用して、プロキシをSpring Bean として定義する

CXFのフロントエンドを使用して、プロキシを動的に生成するめの定義を行います。プロントエンドの使用手順も非常にシンプルで、JaxWsProxyFactoryBeanクラスのインスタンスのプロパティにSEIのFQCNとWSDLのアドレスを指定し、createメソッドをコールするだけです。

src/main/resources/requestor-beans.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws"
	xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">

	<import resource="classpath:META-INF/cxf/cxf.xml" />
	<import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" />

	<bean id="calculate" class="jp.opensquare.sandbox.cxf.jaxws.provider.Calculate" factory-bean="calculateProxyFactory"
		factory-method="create" />

	<bean id="calculateProxyFactory" class="org.apache.cxf.jaxws.JaxWsProxyFactoryBean">
		<property name="serviceClass" value="jp.opensquare.sandbox.cxf.jaxws.provider.Calculate" />
		<property name="address" value="http://localhost:8080/cxf-jaxws/CalculateService" />
	</bean>
</beans>


サービスリクエスタを作成する

サービスリクエスタでは、CXFのフロントエンドで生成したプロキシを使用してサービスコールを行います。コードをみてわかるようにSpringのコンテナ上からプロキシを取得し、メソッドをコールするだけです。

src/main/java/jp/opensquare/sandbox/cxf/jaxws/requestor/ServiceRequestor.java

package jp.opensquare.sandbox.cxf.jaxws.requestor;

import java.util.ArrayList;
import java.util.List;

import jp.opensquare.sandbox.cxf.jaxws.provider.Calculate;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class ServiceRequestor {
	public static void main(String[] args) {
		ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("requestor-beans.xml");

		Calculate requestor = (Calculate) context.getBean("calculate");
		List<Integer> values = new ArrayList<Integer>();
		values.add(1);
		values.add(2);
		values.add(3);
		System.out.println("Sum: " + requestor.sum(values));
		System.exit(0);
	}
}


最後に

Apache CXFはJAX-WS仕様のイケてない点をうまくカバーしており、Apache CXFを使用するだけでJAX-WS仕様のサービス開発も随分とシンプルになります。Apache CXFは、他にもパワフルで便利な機能がたくさんありますので、機会があれば紹介したいと思います。

ソースコードの取得

紹介したソースコードは、https://github.com/rising3/cxf-jaxwsから取得できます。


あわせてお読みください