SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

japan.internet.com翻訳記事

SpringのAOPフレームワークを使ってロギングをアスペクトとして実装する

Springによる軽量で再利用可能なロギング機能の実装

  • X ポスト
  • このエントリーをはてなブックマークに追加

ロギングをAOPとして設定する

 リスト1は、Springを用いてコンポーネントとサービスを結び付ける構成ファイルです。

リスト1 Spring用XML構成ファイルの例
<bean id="maintenanceServiceBean"
      class="org.springframework.aop.framework.ProxyFactoryBean">
    <property name="proxyInterfaces">
        <value>IMaintenanceService</value>
    </property>
    <property name="target">
        <ref bean="maintenanceServiceImpl"/>
    </property>
    <property name="interceptorNames">
        <list>
            <value>loggingInterceptor</value>
        </list>
    </property>
</bean>

<bean id=" maintenanceServiceImpl " class="MaintenanceService">

<bean id=" loggingInterceptor"  class="LoggingInterceptor"/>

 SpringにビルトインされたAOPインフラストラクチャは、「org.springframework.aop.*」パッケージで定義されています。SpringはFactoryBeanという概念をサポートします。これは、与えられたクラス上でのプレーンなnewInstance()呼び出しというよりも、ファクトリの結果として返される特別なタイプのBeanです。つまり、リスト1の例でProxyFactoryBeanのインスタンスは生成されず、SpringがProxyFactoryBeanオブジェクトと相談してmaintenanceServiceBeanオブジェクトを要求します。これにどんな意味があるのでしょう。このFactoryBeanという概念は、SpringがBeanをラップし、(動的プロキシやCGLIBなどの内部ツールを用いて)そのBeanのためのプロキシを生成し、それがメソッド呼び出しに対してアドバイスを実行するというものです。アドバイスの実行は、当該メソッドがジョインポイントであるとポイントカットが表明したときに行われます(ポイントカットが定義されている場合)。ジョインポイントとは、メソッド呼び出しや例外スローなどのプログラム実行ポイントのことです。今回のサンプルに即して、一連の流れを説明しておきましょう。maintenanceServiceBeanオブジェクトが要求されると、コンテナは、ターゲットのmaintenanceServiceImplに対する呼び出しをインターセプトするオブジェクトを返します。これにより、メソッド呼び出しを先に処理するチャンスがLoggingInterceptorに与えられます。LoggingInterceptorの処理が完了すると、制御はmaintenanceServiceImplに戻り、元のタスクが実行されます。

 interceptorNamesプロパティは、プロキシファクトリBeanがプロキシ対象のBeanにどのアドバイザ(またはアドバイスオブジェクト)を適用するかを定義するものです。このプロパティのリストでは順番に意味があります。このリスト内での順番によって、Beanの開始時および終了時に呼び出されるアドバイザまたはアドバイスオブジェクトの順番が決まります。リスト1のアドバイスオブジェクトはloggingInterceptorです。これをプロキシ対象のmaintenanceServiceBeanに適用する必要があります。

 リスト2は、LoggingInterceptorクラスのコードです。

リスト2 LoggingInterceptorクラス
import java.lang.reflect.Method;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.aop.AfterReturningAdvice;
import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.aop.ThrowsAdvice;

public class LoggingInterceptor implements MethodBeforeAdvice,
    AfterReturningAdvice, ThrowsAdvice{
    private static Log log = null;
    public LoggingInterceptor(){
    }

    public void before(Method arg0, Object[] arg1, Object arg2)
        throws Throwable {
        log = LogFactory.getLog(arg2.getClass());
        log.info("Beginning method: "+arg0.getName());
    }

    public void afterReturning(Object arg0, Method arg1,
        Object[] arg2, Object arg3) throws Throwable {
        log = LogFactory.getLog(arg3.getClass());
        log.info("Ending method: "+arg1.getName());
    }

    public void afterThrowing(Method m, Object[] args,
        Object target, Throwable ex)
    {
        log = LogFactory.getLog(target.getClass());
        log.info("Exception in method: "+m.getName()+
            " Exception is: "+ex.getMessage());
    }

}

 LoggingInterceptorクラスは、SpringのAOPフレームワークの3つのインターフェイス、すなわちMethodBeforeAdviceAfterReturningAdviceThrowsAdviceを実装します。MethodBeforeAdviceインターフェイスは、ターゲットメソッドの起動前に呼び出すアドバイスオブジェクトで実装します。その際に、このインターフェイスに用意されているvoid before (Method arg0, Object [] arg1, Object arg2) throws Throwableメソッドを実装しなければなりません。beforeメソッド内部のコードはターゲットメソッドよりも先に実行されます。そのため、リスト2にはメソッド呼び出しのロギングに必要なコードが含まれています。

 同様にAfterReturningAdviceインターフェイスは、ターゲットメソッドの後で呼び出すアドバイスオブジェクトで実装します。このインターフェイスのvoid afterReturning (Object arg0, Method arg1, Object [] arg2, Object arg3) throws Throwableメソッドは、ターゲットメソッドの後で実行されます。

 最後のThrowsAdviceインターフェイスは、ターゲットメソッドが例外をスローしたときに呼び出すアドバイスオブジェクトで実装します。このインターフェイスのvoid afterThrowing(Method m, Object[] args, Object target, Throwable ex)メソッドは、ターゲットメソッドが例外をスローしたときに実行されます。

 一般的なロギング機能では、メソッドの入り口と出口、それに例外をトレースする必要があるので、LoggingInterceptorクラスは上記の3つのインターフェイスを実装して、これらのタスクを遂行します。

選択的なロギングのための設定

 リスト1は、ターゲットのBeanのすべてのメソッド呼び出し(Beanインターフェイスの中で定義されているもの全部)にロギングを編み込む場合の設定を示しています。では、特定のメソッド呼び出しだけを選択的にトレースするにはどうすればよいでしょうか。このシナリオは、セキュリティやトランザクション、監査証跡など、横断的関心事を選択的に適用する場面に向いています。

 リスト3に、選択的なロギングのための設定を示します。

リスト3 選択的なロギングのためのXML構成ファイル
<bean id="maintenanceServiceBean"
    class="org.springframework.aop.framework.ProxyFactoryBean">
    <property name="proxyInterfaces">
        <value>IMaintenanceService</value>
    </property>
    <property name="target">
        <ref bean="maintenanceServiceImpl"/>
    </property>
    <property name="interceptorNames">
        <list>
            <value> theLogger </value>
        </list>
    </property>
</bean>
<bean id="theLogger"
    class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
    <property name="advice">
        <ref local=" loggingInterceptor "/>
    </property>
    <property name="patterns">
        <value>.*getList.*,.*getCounts.*</value>
    </property>
</bean>

<bean id=" maintenanceServiceImpl " class="MaintenanceService">
<bean id=" loggingInterceptor"  class="LoggingInterceptor"/>

 リスト1とリスト3の設定の違いは、リスト3ではロギングインターセプタ(theLogger)がRegexpMethodPointcutAdvisorというSpringクラスをポイントしている点にあります(リスト1ではその実装クラスをポイントしています)。これはつまり、theLoggerは正規表現によるポイントカットを行ってアドバイス(今回のサンプルでは、実際のロギング機構をアドバイスとして実装しているloggingInterceptor)を適用するクラスであり、patternおよびpatternsというプロパティを用いて正規表現パターンを設定できることを意味しています。これらのプロパティによって実際にアドバイスを特定のパブリックメソッド、またはインターセプトされたBeanの各パブリックメソッドに適用することができます。

 patternプロパティは、「.*getList.*」のようなメソッド名のパターンを1つ取ります。このパターンは完全修飾メソッド名でなければなりません。*を指定すると、インターセプトされたBeanのすべてのパブリックメソッドにアドバイスが適用されます。patternsプロパティは、実際はパターンの配列です(例えば、「.*getList.*,.*getCounts.*」のように指定します)。パターンの間はコンマで区切ってください。

強力で柔軟性の高い概念

 SpringのAOPフレームワークを用いてロギングをアスペクトとして実装するというのは強力で柔軟性の高い考え方です。Springは軽量なので、ロギングの実装は単なるPOJOとなり、どのフレームワークとも密に結合されません。そのため、コンテナベースであれ別の軽量フレームワークであれ、どんなシステムでも再利用が可能となります。

 ロギングと同じようなやり方で、その他の横断的関心事も実装できます。例えば、データベースを呼び出す際に監査証跡コンポーネントを起動するといった監査証跡の実装例が考えられます。このような単純な目的なら、監査証跡サービスはSpringのMethodBeforeAdviceインターフェイスを実装し、before()メソッドに必要なコードを記述するだけで済みます。

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加
japan.internet.com翻訳記事連載記事一覧

もっと読む

この記事の著者

japan.internet.com(ジャパンインターネットコム)

japan.internet.com は、1999年9月にオープンした、日本初のネットビジネス専門ニュースサイト。月間2億以上のページビューを誇る米国 Jupitermedia Corporation (Nasdaq: JUPM) のニュースサイト internet.comEarthWeb.com からの最新記事を日本語に翻訳して掲載するとともに、日本独自のネットビジネス関連記事やレポートを配信。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

Gopal Sharma(Gopal Sharma)

Capgemini Indiaのマネージャ。Javaテクノロジに関する豊富な経験を有し、開発者から設計者まで幅広いプロジェクト業務をこなす。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/396 2006/08/22 15:48

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング