1. 概要

このチュートリアルでは、ApacheCXFフレームワークをSpringと一緒にJavaまたはXML構成で構成および使用することに焦点を当てています。

これは、ApacheCXFに関するシリーズの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アーティファクトの最新バージョンについては、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アーティファクトの最新バージョンはここにあります。

最後に、従来の web.xmlデプロイメント記述子の代わりにJavaサーブレット3.0+APIを使用してアプリケーションをプログラムで構成するため、以下のアーティファクトが必要になります。

<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>3.1.0</version>
</dependency>

このは、サーブレット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));

ApacheCXFによって定義される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です。これは、ApacheCXFがSpringFrameworkと連携するための拡張機能を提供します。

@Bean
public SpringBus springBus() {
    return new SpringBus();
}

EnpointImpl Beanも、 SpringBusBeanと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. タイプ定義

次へ–前のサブセクションですでに説明した実装者の定義は次のとおりです。

@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;
    }
}

このクラスは、ApacheCXFが公開された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は、 BaeldungWebサービスのプロキシを表します。 これは、JAX-WSプロキシを作成するためのファクトリであるJaxWsProxyFactoryBeanBeanで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. テストケース

このセクションでは、SpringのApacheCXFサポートを説明するために使用されるテストケースについて説明します。 テストケースは、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ファイルでpackagesプロパティを宣言することで実現できます。

<packaging>war</packaging>

パッケージ化ジョブは、MavenWARプラグインによって実装されます。

<plugin>
    <artifactId>maven-war-plugin</artifactId>
    <version>2.6</version>
    <configuration>
        <failOnMissingWebXml>false</failOnMissingWebXml>
    </configuration>
</plugin>

このプラグインは、コンパイルされたソースコードをWARファイルにパッケージ化します。 Javaコードを使用してサーブレットコンテキストを構成するため、従来のweb.xmlデプロイメント記述子が存在する必要はありません。 その結果、プラグインの実行時の失敗を回避するために、failOnMissingWebXmlプロパティをfalseに設定する必要があります。

Maven WARプラグインの最新バージョンについては、このリンクをたどることができます。

Webサービスの操作を説明するために、統合テストを作成します。 このテストでは、最初にWARファイルを生成して組み込みサーバーを起動し、次にクライアントにWebサービスを呼び出させ、後続の応答を検証して、最後にサーバーを停止します。

次のプラグインをMavenPOMファイルに含める必要があります。 詳細については、この統合テストチュートリアルをご覧ください。

MavenSurefireプラグインは次のとおりです。

<plugin>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>2.22.2</version>
    <configuration>
        <excludes>
            <exclude>StudentTest.java</exclude>
        </excludes>
    </configuration>
</plugin>

このプラグインの最新バージョンはここにあります。

統合テストを容易にするために、統合idを持つプロファイルセクションが宣言されています。

<profiles>
   <profile>
      <id>integration</id>
      <build>
         <plugins>
            ...
         </plugins>
      </build>
   </profile>
</profiles>

Maven Cargoプラグインは、統合プロファイルに含まれています。

<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構成プロパティは、わかりやすくするために含まれているだけであることに注意してください。 これらの構成プロパティは、値がデフォルト値と同じであるため、アプリケーションに影響を与えることなく省略できます。 このプラグインはサーバーを起動し、接続を待機し、最後にサーバーを停止してシステムリソースを解放します。

このリンクを使用すると、MavenCargoプラグインの最新バージョンを確認できます。

Maven Surefireプラグインは、 Integration プロファイル内で再度宣言され、メインの build セクションの構成をオーバーライドし、前のセクションで説明したテストケースを実行します。

<plugin>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>2.22.2</version>
    <executions>
        <execution>
            <phase>integration-test</phase>
            <goals>
                <goal>test</goal>
            </goals>
            <configuration>
                <excludes>
                    <exclude>none</exclude>
                </excludes>
            </configuration>
        </execution>
    </executions>
</plugin>

これで、プロセス全体を次のコマンドで実行できます: mvn -Pintegration cleaninstall

7. 結論

このチュートリアルでは、Springに対するApacheCXFのサポートについて説明しました。 特に、Spring構成ファイルを使用してWebサービスを公開する方法と、別の構成ファイルで宣言されたApacheCXFプロキシファクトリによって作成されたプロキシを介してクライアントがそのサービスと対話する方法が示されています。

これらすべての例とコードスニペットの実装は、リンクされたGitHubプロジェクトにあります。