Apache CXF を使用して Web サービス・メッセージのロギングを実行する
Apache CXF を使用して Web サービス・メッセージのロギングを実行する方法を学ぶ
概要
Apache CXF は Web サービスの開発、ビルド、デプロイに使用される Web サービス・フレームワークです。CXF は多くの機能をサポートしており、開発者はそれらの機能を使用して Web サービス・ベースのアプリケーションの開発やデプロイを行うことができます。そうした機能の 1 つがロギングです。ここで言うロギングは、実質的には Web サービス・メッセージのロギングを意味します。CXF は標準的な Java ロギング API を使用してメッセージのロギングを行います。この方法により、受信メッセージと送信メッセージの両方のログを取ることができます。メッセージのロギングはクライアント・サイドでもサーバー・サイドでも行うことができます。ロギングによって、サーバーとの間で送受信される実際の SOAP ペイロードを見ることができるため、ロギングは重要であり、デバッグ・ツールとしても役に立ちます。CXF でロギングを実装する場合、インターセプターとフィーチャーという概念を使用します。この記事では、それらの概念を使用して単純に Web サービス・メッセージのロギングを実行する方法について説明します。また、Spring ベースの Bean 構成を使用してメッセージ・ロギングを構成する方法についても説明します。
ここでは、JAX-WS フロントエンド、つまり CXF の API を使用する単純な Web サービスを作成します。Web サービスとしては、オンラインの LMS
(Learning Management System: 学習管理システム) を考えてみましょう。LMS
の機能には通常、ユーザー管理、コース作成、ディスカッション・フォーラム、成績表管理、コンテンツ管理などが含まれます。この記事では、「コース作成」を例として取り上げ、CourseBuilder
という単純な Web サービス・クラスを作成します。またこの記事では、単純な Web サービスを作成して JAX-WS
エンドポイントとして公開する方法を間接的に示します。ただし基本的な目標は、ロギング・メカニズムを示すことです。この記事ではサーバー・サイドのロギングのみに焦点を絞ります。サーバー・サイドのロギングを理解できると、クライアント・サイドのロギングを容易にエミュレートすることができます。
この Web サービス・クラスは以下のようなものです。
リスト 1. CourseBuilderImpl Web サービス・クラス
@WebService public class CourseBuilderImpl implements CourseBuilder { public String createCourse(Course course) { System.out.println("Course code is " + course.getCode()); System.out.println("Course title is " + course.getTitle()); return "Course created successfully"; } }
上記の Web サービス・クラス CourseBuilderImpl
は非常に単純です。createCourse
メソッドは Course
という Bean
を引数に取り、コースが適切に作成されたことを示すステータス・ストリングを返します。今度はサービス・メッセージのログをコンソールに表示します。サービス・メッセージは実質的に SOAP
ペイロード、つまりメソッド・パラメーターと戻り型という形式による実際のデータを意味しています。ロギング機能を有効にすることで、このペイロードをコンソールに表示することができます。
インターセプターを使用したロギング
CXF のインターセプターは SOAP メッセージをインターセプトするコンポーネントです。CXF
のインターセプターは受信メッセージも送信メッセージもインターセプトすることができます。従って、これらのインターセプターをクライアント・アプリケーションで構成することも、サーバー・サイドで構成することも、あるいはその両方で構成することもできます。CXF
にはインターセプターがいくつも組み込まれています。メッセージのロギングを実行するインターセプターとしては、LoggingInInterceptor
と LoggingOutInterceptor
があります。これらのインターセプターを使用してサーバー・サイドでロギングを実行します。以下のコードはその方法を示しています。
リスト 2. サーバー・コード
public final class Server { public static void main(String args[]) throws Exception { CourseBuilderImpl implementor = new CourseBuilderImpl(); JaxWsServerFactoryBean svrFactory = new JaxWsServerFactoryBean(); svrFactory.setAddress("http://localhost:9000/CourseBuilder"); svrFactory.setServiceBean(implementor); svrFactory.getInInterceptors().add(new LoggingInInterceptor()); svrFactory.getOutInterceptors().add(new LoggingOutInterceptor()); svrFactory.create(); } }
上記のコードは JaxWsServerFactoryBean
サーバー・ファクトリー・クラスを使用して
CourseBuilder
サービスを JAX-WS
エンドポイントとして公開します。ご覧のとおり、このコードは実装クラスとエンドポイントのアドレスを設定しています。create
メソッドは、組み込みのスタンドアロン Jetty サーバーを起動します。このコードの重要な部分は太字で強調してあります。強調した部分では、2 つのインターセプター、つまり
LoggingInInterceptor
と
LoggingOutInterceptor
を使用しています。これらがファクトリー・クラスに追加された後、create
メソッドが呼び出されます。この強調されたコードにより、受信メッセージと送信メッセージの両方に対してサーバー・サイドのロギング機能が有効になります。クライアント・アプリケーションを実行すると、サーバー・コンソールには以下の出力がログとして表示されます。
図 1. サーバー・コンソール

上記のサーバー・コンソール出力は、受信した SOAP ペイロードと送信した SOAP
ペイロードを示しています。また、ログの内容に関する最大サイズをコンストラクターの中で指定して制御することもできます。サイズはバイト数を表しており、例えば
new LoggingInInterceptor(1024)
のように指定します。これを見るとわかるように、ロギング・インターセプターを利用すると、サービス・メッセージのロギングが非常に容易になります。また、アノテーションを利用してロギングを実装することもできます。以下のコードはアノテーションとインターセプターを利用してロギングを実装しています。
リスト 3. インターセプター・アノテーションを使用したロギング
@WebService @InInterceptors(interceptors = "org.apache.cxf.interceptor.LoggingInInterceptor") @OutInterceptors(interceptors = "org.apache.cxf.interceptor.LoggingOutInterceptor") public class CourseBuilderImpl implements CourseBuilder { ...
@InInterceptors
と
@OutInterceptors
というアノテーションを使用すると、それぞれ受信インターセプターと送信インターセプターを定義することができます。アノテーションの宣言は、サービス・クラスまたは SEI
(Service Endpoint Interface) の中で行います。これらのアノテーションが SEI
の中にあると、クライアント・アプリケーションとサーバー・アプリケーションの両方でロギング機能が有効になります。上記のコードでは
CourseBuilderImpl
サービス実装クラスでアノテーションが宣言されているため、サーバー・サイドのみでメッセージ・ロギングが実行されます。
フィーチャーを使用したロギング
CXF のフィーチャーの機能はデコレーターとよく似ています。CXF
のフィーチャーは、クライアント、サーバー、バスのコンポーネントに適用されます。フィーチャーは基本的に、クライアント、サーバー、またはバスの機能を拡張します。CXF
にはフィーチャーの実装がいくつか組み込まれており、その 1 つが LoggingFeature
クラスです。LoggingFeature
クラスは SOAP
メッセージのロギングを実行します。ここでは、先ほど示したサーバー・コードを再度取り上げます。今度はインターセプターの代わりに
LoggingFeature
クラスを使用します。
リスト 4. ロギング・フィーチャー
public final class Server { public static void main(String args[]) throws Exception { CourseBuilderImpl implementor = new CourseBuilderImpl(); JaxWsServerFactoryBean svrFactory = new JaxWsServerFactoryBean(); svrFactory.setAddress("http://localhost:9000/CourseBuilder"); svrFactory.setServiceBean(implementor); svrFactory.getFeatures().add(new LoggingFeature()); svrFactory.create(); } }
強調されたコードがすべてを語っています。このコードは受信メッセージと送信メッセージの両方、つまりサーバーが受信したメッセージとサーバーが返した応答をログとして記録します。そして
LoggingFeature
クラスはロギング・インターセプターを使用します。ただしインターセプターを直接使用した方が、より詳細な制御が可能です。例えば受信メッセージのみをログに記録し、送信メッセージを記録したくない場合には、LoggingInInterceptor
インターセプター・クラスのみを使用すればよく、LoggingFeature
クラスを使用する必要はありません。ロギング・インターセプターの場合とまったく同じように、LoggingFeature
クラスを使用すると、ロギングの内容のサイズをバイト数で制限することができます。制限サイズを指定するためには、コンストラクターの中で以下のようにします。
リスト 5. サイズ制限を付けたロギング・フィーチャー
public final class Server { public static void main(String args[]) throws Exception { JaxWsServerFactoryBean svrFactory = new JaxWsServerFactoryBean(); ... // This will only log upto 1K or 1024 characters svrFactory.getFeatures().add(new LoggingFeature(1024)); ... } }
また LoggingFeature
クラスを使用すると、ロギング対象のメッセージの出力先を設定することができます。構成により、メッセージ・ロギングの出力先を stdout (コンソール)、stderr
(エラー・コンソール)、またはファイルに設定することができます。出力先は受信メッセージに対しても送信メッセージに対しても設定することができます。以下のコードは
LoggingFeature
クラスで出力先を使用する場合を示しています。
リスト 6. 出力先を指定したロギング・フィーチャー
public final class Server { public static void main(String args[]) throws Exception { JaxWsServerFactoryBean svrFactory = new JaxWsServerFactoryBean(); ... svrFactory.getFeatures().add( new LoggingFeature("<stdout>", "file://home/myLog.txt")); ... } }
先ほどとは別の、上記の LoggingFeature
コンストラクターは、2
つのストリング・パラメーターを引数に取ります。これらのパラメーターはそれぞれ、受信メッセージと送信メッセージのログの出力先を示します。上記のコードから、受信メッセージのログはコンソールに出力され、送信メッセージのログはファイルに出力されます。
フィーチャーにもアノテーションを使用することができます。@Features
アノテーションを使用すると、フィーチャーを指定することができます。以下のコードは @Features
アノテーションの使い方を示しています。
リスト 7. アノテーションを使用したロギング・フィーチャー
@WebService @Features(features = "org.apache.cxf.feature.LoggingFeature") public class CourseBuilderImpl implements CourseBuilder { ...
上記のコードでは、@Features
アノテーションを使用して
LoggingFeature
クラスを指定し、サーバー・サイドでロギングを実行しています。
インターセプター・アノテーションやフィーチャー・アノテーションを使いたくない場合には、単純に @Logging
アノテーションを使用してメッセージ・ロギングを実行することができます。以下のコードを使用すると、ロギングをさらに簡単に実行できるようになります。
リスト 8. @Logging アノテーション
@WebService @Logging public class CourseBuilderImpl implements CourseBuilder { ...
Spring ベースの Bean 構成を使用したロギング
CXF では、Spring ベースの Bean 構成ファイルを使用して Web サービスを公開することもできます。Spring 構成ファイルを使用することによる当然のメリットとして、サービス Bean にフィーチャーとインターセプターを動的に追加することができ、コードを再コンパイルする必要がありません。私が以前に寄稿した、Apache CXF と Spring を使用した Web サービスの開発に関する記事を読むことをお勧めします。その記事では、Spring 構成ファイルを使用して Web サービスを作成し、最終的にその Web サービスを公開する手順を説明しています。
以下のコードは CourseBuilderImpl
Bean を JAX-WS
エンドポイントとして定義する構成ファイルを示しています。
リスト 9. CourseBuilderImpl サービス Bean を JAX-WS エンドポイントとして定義する
<?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.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd"> <jaxws:endpoint id="courseBuilder" implementor="demo.cxf.logging.CourseBuilderImpl" address="/CourseBuilder" /> </beans>
<jaxws:endpoint>
要素を使用することで、CourseBuilderImpl
サービス Bean を JAX-WS
エンドポイントとして定義しています。エンドポイントの URL はWeb コンテンツに対する相対 URL です (これは http トランスポートとして
CXFServlet
を使用している場合には当然です)。ここで、ロギング・インターセプターを使用するためには、上記のコードを以下のように変更する必要があります。
リスト 10. ロギング・インターセプターを構成する
<beans> ... <bean id="logIn" class="org.apache.cxf.interceptor.LoggingInInterceptor"/> <bean id="logOut" class="org.apache.cxf.interceptor.LoggingOutInterceptor"/> <jaxws:endpoint id="courseBuilder" implementor="demo.cxf.logging.CourseBuilderImpl" address="/CourseBuilder" > <jaxws:inInterceptors> <ref bean="logIn"/> </jaxws:inInterceptors> <jaxws:outInterceptors> <ref bean="logOut"/> </jaxws:outInterceptors> </jaxws:endpoint> </beans>
変更された上記のコードには、2 つのインターセプター Bean、つまり LoggingInInterceptor
と
LoggingOutInterceptor
が追加されています。これらの Bean の参照が、それぞれ
<jaxws-inInterceptors>
要素と
<jaxws-outInterceptors>
要素を使用して
CourseBuilderImpl
サービス Bean
に渡されています。こうすることで、必ず受信サービス・メッセージと送信サービス・メッセージの両方のロギングが実行されます。
同様に、Spring を利用してロギング・フィーチャーを構成することもできます。以下のコードはロギング・フィーチャーを示しています。
リスト 11. ロギング・フィーチャーを構成する
<beans> ... <jaxws:endpoint id="courseBuilder" implementor="demo.cxf.logging.CourseBuilderImpl" address="/CourseBuilder" > <jaxws:features> <bean class="org.apache.cxf.feature.LoggingFeature"/> </jaxws:features> </jaxws:endpoint> </beans>
上記のコードを見るとわかるように、<jaxws:features>
要素を使用してロギング・フィーチャーを指定しています。
以上の内容を要約すると、この記事ではインターセプターやフィーチャーなど、CXF のネイティブ機能を利用してサービス・メッセージのロギングを実行する方法を詳しく探りました。アノテーションを使用することで、また Spring ベースの Bean 構成を使用することで、プログラムでメッセージ・ロギングを実行することができます。Apache CXF フレームワークは、Log4j や SLF4J などのロギング・フレームワークと統合することができ、Web サービス・ランタイムのためのさまざまなデバッグ・ツールもサポートしています。CXF を使用したロギングやデバッグについての詳細は、Apache CXF の「Debugging and Logging」を参照してください。