SHOEISHA iD

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

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

特集記事

AspectDNGで始める.NETのAOP

AspectDNGでS2Container.NETを機能拡張してみる

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

本稿では、.NET用のアスペクト指向プログラミング(AOP)ツール「AspectDNG」を紹介します。AspectDNGは、非常に使い易く、JavaのAspectJやJBossAOPと比べてもひけをとらないツールです。

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

はじめに

 ようやく一般化しつつある感のあるAOP(Aspect Oriented Program:アスペクト指向プログラム)ですが、AspectJや、JBossAOPなどの代表的なAOPツールが存在するJavaに比べて、.NETはツールも技術情報も少ない状況で、まだまだ未成熟な印象を受けます。

 しかし、未成熟ながらも、.NETのAOP環境において、AspectJやJBossAOPにもひけをとらず、使い勝手の良いAspectDNGというツールがあります。本稿ではAspectDNGの持つ機能や使い方などを紹介します。

記事の全体像(クリックすると拡大されます)
記事の全体像(クリックすると拡大されます)

対象読者

 この記事は、次のような方を対象としています。

  • AOPの基本的な概念を理解している
  • .NETでのAOPに興味がある

必要な環境

AspectDNGの紹介

 AspectDNGはGPLライセンスのオープンソースソフトウェアで、AspectDNGのプロジェクトは、SourceForge.net、DotNetGuruを経て、現在、Tigris.orgにホスティングされています。

 主な特徴は次の通りです。

  • .NETアセンブリ(.exeや.dll)にウィービング可能
  • アスペクト対象とアスペクト定義クラスのアセンブリを分離可能
  • 通常のクラスを使ってアスペクトを定義可能
  • アドバイスの定義に.NETカスタムアトリビュートと外部XMLファイルを使用可能
  • アドバイスに設定するクエリ文字列として、XPathと簡易型の正規表現が使用可能
  • インタータイプ宣言が可能
    • 既存タイプ(クラスなど)へのメソッド、フィールド、プロパティ、内部タイプの追加
    • アセンブリへのタイプ(クラスなど)の追加
  • GAOP(Generic AOP)機能
  • MonoプロジェクトのCecilを使ってアセンブリへの操作を実施

ロギング処理をウィービング

 定番的なロギング処理のウィービングを通して、AspectDNGの基本的な使い方を紹介していきます。

アスペクトの適用対象とするクラスを作成

 アスペクトのウィービング対象となるクラスを作成します。プロパティXYに設定された数値を加算し結果を返すAddメソッドだけを持つ簡単なクラスです。

Calc.cs
using System;

public class Calc
{
    private int x;
    private int y;

    public int X
    {
        get
        {
            return this.x;
        }
        set
        {
            this.x = value;
        }
    }

    public int Y
    {
        get
        {
            return this.y;
        }
        set
        {
            this.y = value;
        }
    }

    public int Add()
    {
        return this.x + this.y;
    }

    public static void Main(string[] args)
    {
        Calc calc = new Calc();

        calc.X = 100;
        calc.Y = 50;

        Console.WriteLine("{0} + {1} = {2}", calc.X, calc.Y, calc.Add());
    }
}

アスペクトの定義クラスを作成

 AspectDNGのカスタムアトリビュートを使って、Calcクラスのプロパティやメソッドの呼び出し時に、ロギングを実施するアドバイスを定義したアスペクトクラスを作成していきます。

AspectDNGのアドバイス定義

 アスペクトのクラスを作成する前に、AspectDNGにおけるアドバイスの定義方法を簡単に説明します。

 AspectDNGではアドバイスの定義に、XMLファイルとカスタムアトリビュートを使う方法があり、カスタムアトリビュートは、次のようなものが用意されています(カスタムアトリビュートは、アドバイスごとに決められたシグネチャのメソッドに指定します)。

  • [AroundBody("query")]
  • [AroundCall("query")]
  • [AroundFieldRead("query")]
  • [AroundFieldWrite("query")]
  • [Insert("query")]
  • [Warning("query")]
  • [Error("query")]
  • [SetBaseType("query")]
  • [ImplementInstance("query")]
  • [Generic("query")]

 上記のquery部分にはXPathと簡易型の正規表現のどちらかが使用でき、正規表現には次のような記述が可能です。

  • SomeReturnType SomeNamespace.SomeType::SomeMethod(FirstParamType, SecondParamType, *)
  • *::{MethodName|OtherMethodName}(OnlyParamType)
  • *::FieldName

 アドバイス指定先メソッドのシグネチャは、アドバイスの種類によって異なります。AroundBodyAroundCallの場合は、以下のメソッドシグネチャが使用可能です。

AroundBody、AroundCallアドバイスのメソッドシグネチャ
//(注)Interceptorの部分は任意のメソッド名が使用可能
// 引数はターゲットによって変更可

//ターゲットがメソッドと分かっている場合
public static object Interceptor(MethodJoinPoint jp)

//ターゲットがコンストラクタと分かっている場合
public static object Interceptor(ConstructorJoinPoint jp)

//ターゲットがメソッドかコンストラクタか不明な場合
public static object Interceptor(OperationJoinPoint jp)

アスペクトクラスLogAspectの作成

 それでは、アスペクトの定義クラスを作成していきます。

 Calcクラスの全メソッドと、コンストラクタの呼び出し位置をジョインポイントとするAroundCallアドバイスを指定したInterceptメソッド、Calcクラスの全プロパティ取得の実行位置をジョインポイントとするAroundBodyアドバイスを指定したInterceptPropertyメソッドを定義します。

LogAspect.cs
using System;
using DotNetGuru.AspectDNG.Joinpoints;

public class LogAspect
{
    //Calcクラスの全メソッドと
    //コンストラクタの呼び出し位置にウィービング
    [AroundCall("* Calc::*(*)")]
    public static object Intercept(OperationJoinPoint jp)
    {
        Console.WriteLine("--- before call : {0}", jp);
        return jp.Proceed();
    }

    //Calcクラスの全プロパティ取得の実行位置にウィービング
    [AroundBody("* Calc::get_*()")]
    public static object InterceptPorperty(MethodJoinPoint jp)
    {
        Console.WriteLine("--- before property get : {0}", jp);
        return jp.Proceed();
    }
}

アスペクトのウィービング

事前準備

 AspectDNGのサイトから、Binary distributionをクリックし、最新の「aspectdng-latest-bin.zip」ファイルをダウンロードし、適当なディレクトリに解凍します。

 解凍先ディレクトリ内の、「2.0\aspectdng.exe」をサンプルを作成するディレクトリにコピーしておきます。

ビルドと実行

 参照先に「aspectdng.exe」を指定して「Calc.cs」と「LogAspect.cs」をビルドし「Calc.exe」を作成します

ビルド
>csc /r:aspectdng.exe Calc.cs LogAspect.cs

 この段階ではCalcクラスに対してアスペクトはウィービングされていないため、実行結果は次のようになります。

実行結果
>Calc.exe
100 + 50 = 150

アスペクトのウィービング

 引数に「Calc.exe」を指定して「aspectdng.exe」を実行することで、アスペクトウィービング後の「Calc.exe」と、元の「Calc.exe」のバックアップである「Calc.exe.backup」が作成されます。

アスペクトのウィービング
>aspectdng.exe Calc.exe

ウィービング後の実行

 ウィービング後の「Calc.exe」の実行結果は次のようになり、アスペクトが適用されていることを確認できます。

実行結果
>Calc.exe
--- before call : constructor Calc()
--- before call : instance method Calc::set_X(100)
--- before call : instance method Calc::set_Y(50)
--- before call : instance method Calc::get_X()
--- before property get : instance method Calc::get_X()
--- before call : instance method Calc::get_Y()
--- before property get : instance method Calc::get_Y()
--- before call : instance method Calc::Add()
100 + 50 = 150

MSIL 逆アセンブラの実施

 次に、ウィービング後の「Calc.exe」の内部構成にどのような変化が加わったかをMSIL逆アセンブラ(ildasm.exe)を使って確認してみることにします。

逆アセンブラの実行
>ildasm Calc.exe

 実行結果は次のようになり、ジョインポイントごとにAspectDNG関係のメソッドが多数追加されていることを確認できます。

ildasm.exeの実行結果
ildasm.exeの実行結果

会員登録無料すると、続きをお読みいただけます

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

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

メールバックナンバー

次のページ
S2Container.NETのdiconファイルを拡張

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

  • X ポスト
  • このエントリーをはてなブックマークに追加
特集記事連載記事一覧

もっと読む

この記事の著者

和田 好朗(ワダ ヨシアキ)

ITアーキテクト目指して奮闘中。新技術には目が無い技術者。

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

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

この記事をシェア

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

おすすめ

アクセスランキング

アクセスランキング

イベント

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

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

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

メールバックナンバー

アクセスランキング

アクセスランキング