Hatena::ブログ(Diary)

_development, RSSフィード Twitter

2011-06-20

Aspect Oriented Programming("AOP") in Android

Aspect Oritented Programming("AOP")とは?

 AOP(Aspect Oritented Programming, アスペクト指向プログラミング)は、OOP(Object Oriented Programming, オブジェクト指向プログラミング)で表現されたクラスを横断("cross-cutting")する特性を表現するために考案されました。

 たとえば、ロギングのようなメソッド呼び出しのトラッキングプログラム全体で共通した特性ですが、クラスとして表現された特性とは、軸の異なる特性です。

 OOPのみに頼る場合、Templateパターン、Proxyパターンなどのデザインパターンを使って体系だったロギングを行ったりします。また、処理の要所でロギングコードを直接記述したりもします。

 これらは、本来的にはクラスに実装されるべき処理とは無関係であることは明白でしょう。AOPはこのような特性を、クラスとは独立して記述できます。

 つまり、こんなコードを...

public class MyActivity extends Activity {

	@Override
	public void onCreate(Bundle savedInstanceState) {
		Log.d("HelloAJ", ">> execution(void MyActivity.onCreate(Bundle))");
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
	}
}

 元のコードと...

 

public class MyActivity extends Activity {

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
	}
}

 ロギングに分けて記述できるのです。

Log.d("HelloAJ", ">> execution(void MyActivity.onCreate(Bundle))");


AspectJ

 AspectJは、Java VMをターゲットに作成されたAOP言語です。

 AspectJJavaバイトコードを操作することによって、Aspectをクラスに織り込み("weaving")ます。

このような特性のため、AndroidのDEXプロセスのまえにAspectJのweavingを行うことによって、AndroidでもAspectJを使えます。

 

 まず、AspectJでの実例を示しましょう。

以下は、ActivityのonCreate(Bundle)メソッドの呼び出しをロギングするAspectです。

package com.example.android.aj;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;

@Aspect
public class MyAspect {

	/**
	 * @param thisJoinPoint
	 * @see Activity
	 * @see Bundle
	 */
	@Before("execution(void Activity+.onCreate(Bundle))")
	public void beforeOnCreate(JoinPoint thisJoinPoint) {
		Log.d("HelloAJ", ">> " + thisJoinPoint);
	}
}

 AspectJでのAspectの記述方法には二つあります。ひとつは、AspectJのための.ajファイルに記述する方法、もうひとつはAnnotationで記述する方法です。ここでは後者のAnnnotationで記述する方法を使っています。

 クラスに@Aspectを注釈して、このクラスがAspectであることを表明しています。

 次にロギングメソッドbeforeOnCreate()を作成し、ロギング処理を実装します。

引数のJoinPointは、メソッドの実行時コンテキストを表します。

 最後に、@Beforeをメソッドに注釈して、Aspectのweavingを指定するpointcutを記述します。

ここで指定しているのは、ActivityのonCreate()メソッドの実行です。


 次のActivityにAspectがweavingされると...

public class MyActivity extends Activity {

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
	}
}

 こんな感じになります(バイトコードレベルで)。

public class MyActivity extends Activity {

	@Override
	public void onCreate(Bundle savedInstanceState) {
		Log.d("HelloAJ", ">> execution(void MyActivity.onCreate(Bundle))");
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
	}
}

AspectJ Development Tool("AJDT")

 AJDTはAspectJのためのEclipseプラグインです。

AJDTを使えば、AspectのweavingをEclipseビルドプロセスに組み込めます。

また、Aspectの適用結果をグラフィカルに相互参照することもできます。

インストール

  Eclipse Marketplaceなどから、AJDTをインストールします。

f:id:esmasui:20110620013147p:image


  Android Projectをつくります。または、既存のAndroid Projectを開きます。

f:id:esmasui:20110620013800p:image

  • 3. AJDTのフィーチャーの追加

  Android ProjectにAJDTのフィーチャーを追加します。

  (プロジェクトを選択 > Configure > Convert to AspectJ Project を選択)

f:id:esmasui:20110620013801p:image

 AspectJ Runtime Libraryがクラスパスに追加されます。

f:id:esmasui:20110620015548p:image

  • 4. ライブラリーの置き換え

  現在のADTは、AspectJ Runtime LibraryをAPKにパッケージしてくれません。

  AJDTに同梱のaspectjrt.jar、またはAspectJからaspectjrt.jarを入手してAspectJ Runtime Libraryと置き換えます。

f:id:esmasui:20110620015549p:image

f:id:esmasui:20110620015550p:image

  さきほどのようなAspectを作成します。

package com.example.android.aj;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;

@Aspect
public class MyAspect {

	/**
	 * @param thisJoinPoint
	 * @see Activity
	 * @see Bundle
	 */
	@Before("execution(void Activity+.onCreate(Bundle))")
	public void beforeOnCreate(JoinPoint thisJoinPoint) {
		Log.d("HelloAJ", ">> " + thisJoinPoint);
	}
}
  • 6.実行

  Android Applicationとして実行します。

  Activityが起動すると、次のようなログが出力されることでしょう。

DEBUG/HelloAJ(2133): >> execution(void com.example.android.aj.MyActivity.onCreate(Bundle))

  出力されない場合は、プロジェクトをCleanするなどしてみてください。


参照