AOPとはAspect Oriented Programmingの略で、
複数のクラスに分散するロジックをモジュールとして抽出し、
外側から織り込む手法です。
例えば、ログ出力の機能を考えてみてください。
ログ出力の処理を複数のクラスに同じように記述するのは、
面倒なだけでなく、ログ出力の処理に仕様変更が入った場合に、
複数のクラスを同じように修正しなければいけないという問題がおきます。
つまり、仕様変更に弱いのです。
このような場合に、ログ出力の処理をモジュールとして抽出し、
個々のクラスからは削除します。
そして、コンパイル時もしくは実行時に抽出したモジュールをバイトコードに埋め込むことで、
あたかもソースコードに記述されているかのように実行することができます。
ログ出力の処理に仕様変更が入った場合も抽出したモジュールを修正するだけですみます。
メンテナンス性が向上することがわかっていただけるでしょう。
プログラム中に挿入されるコードを表します。Interceptorと呼ばれることもあります。
対象となるクラスとAdviceを結合するポイントを表します。
AdviceはJoinpointから引数やメソッドの情報を取得することができます。
どこにJoinpointを設定するのかを定義します。
AdviceとPointcutを関連付けます。
フィールドやメソッドの追加、実装するインタフェースの追加など,クラスの静的な構造を変更します。
クラス名
org.seasar.framework.aop.interceptors.TraceInterceptor
説明
トレース処理を行なうためのInterceptorです。
DateクラスのgetTime()メソッドにTraceInterceptorを適用するための設定ファイルは次のようになります。
<component class="java.util.Date">
<aspect pointcut="getTime">
<component class="org.seasar.framework.aop.interceptors.TraceInterceptor"/>
</aspect>
</component>
クラス名
org.seasar.framework.aop.interceptors.ThrowsInterceptor
説明
例外を共通的に処理するためのInterceptorです。
使用するにはThrowsInterceptorを継承し、Object handleThrowable(Throwable, MethodInvocation)を実装します。
ThrowableにはThrowableの任意のサブクラスを指定することができます。
handleThrowable()はいくつでも定義することができます。
例えば、NullPointerExceptionをキャッチしてメッセージを出力するには、
次のようなInterceptorを作成します。
package examples.aaa.interceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.seasar.framework.aop.interceptors.ThrowsInterceptor;
public class MyThrowableInterceptor extends ThrowsInterceptor {
public void handleThrowable(NullPointerException e, MethodInvocation invocation)
throws Throwable {
System.out.println("ぬるぽ");
throw e;
}
}
クラス名
org.seasar.framework.aop.interceptors.ToStringInterceptor
説明
toString()メソッドでフィールドの情報を出力するためのInterceptorです。
クラス名
org.seasar.framework.aop.interceptors.RemoveSessionInterceptor
説明
セッションに格納されているオブジェクトを、メソッドが正常に終了した(例外が発生しなかった)場合に、 自動的に削除するためのInterceptorです。
メソッドにRemoveSessionアノテーションを指定して使います。
次の例では、hoge()メソッドの呼び出しが正常終了した場合に、 セッションに格納されているfooオブジェクトを削除します。
@RemoveSession("foo")
public void hoge() {
...
}
クラス名
org.seasar.framework.aop.interceptors.InvalidateSessionInterceptor
説明
セッションを、メソッドが正常に終了した(例外が発生しなかった)場合に、 自動的に破棄するためのInterceptorです。 メソッドにInvalidateSessionアノテーションを指定して使います。
次の例では、hoge()メソッドの呼び出しが正常終了した場合に、 HTTPセッションを破棄します。実際には、セッションの破棄はS2Containerの提供するServlet
Filter (S2ContainerFilter) によって行われます。
@InvalidateSession
public void hoge() {
...
}
クラス名
org.seasar.framework.aop.interceptors.DependencyLookupInterceptor
説明
getterメソッドに適用されて、 S2コンテナからルックアップしたコンポーネントを返すインターセプタです。
次の例では、getMyService()メソッドを呼び出すとS2コンテナからルックアップされたMyServiceが返されます。
@DependencyLookup
public MyService getMyService() {
return null;
}
クラス名
org.seasar.framework.aop.interceptors.InterceptorChain
説明
複数のInterceptorをグルーピング化し、再利用しやすくします。複数のInterceptorの組み合わせを複数コンポーネントに適用する場合は、InterceptorChainで複数のInterceptorを1つにまとめて、各コンポーネントにはInterceptorChainを指定するようにするといいでしょう。
<component name="interceptor1" .../>
<component name="interceptor2" .../>
<component name="interceptor3" .../> <component name="chain" class="org.seasar.framework.aop.interceptors.InterceptorChain"> <initMethod name="add"><arg>interceptor1</arg></initMethod> <initMethod name="add"><arg>interceptor2</arg></initMethod> <initMethod name="add"><arg>interceptor3</arg></initMethod> </component>
<component ...>
<aspect>chain</aspect>
</component>
<component ...>
<aspect>chain</aspect>
</component>
クラス名
org.seasar.framework.aop.interceptors.InterceptorLifecycleAdapter
説明
Interceptorはアスペクトをクラスに組み込む際にインスタンス化されるため、singleton以外の場合は意図したとおりに動作しません。
このような場合は、InterceptorLifecycleAdapterをMethodInterceptorのinvoke()メソッドに適用します.
<component name="myInterceptor" instance="prototype" .../>
<aspect pointcut="invoke">
<component class="org.seasar.framework.aop.interceptors.InterceptorLifecycleAdapter">
</aspect>
</component>
<component ...>
<aspect>myInterceptor</aspect>
</component>
説明
独自にInterceptorを作成する場合は、次のインターフェースまたは、抽象クラスを実装します。
- org.aopalliance.intercept.MethodInterceptor
- org.seasar.framework.aop.interceptors.AbstractInterceptor
どちらの場合も実装するメソッドは、以下のinvoke()メソッドの1つだけです。
- public Object invoke(MethodInvocation invocation) throws Throwable
AbstractInterceptorは、MethodInterceptorをimplementsした抽象クラスです。
AbstractInterceptor.getTargetClass()で、
アスペクトを適用する前のクラスを知ることができます。
MethodInvocationのgetThis()、getMethod()、getArguments()で、
対象となるオブジェクト、メソッド、引数を取得できます。
getThis()でクラス名を取得するとバイトコードで組み込まれたクラス名が取得されます。
proceed()を呼び出すと実際のメソッドが呼び出され実行結果を取得することができます。
実際のメソッドを呼び出す前後にログを出力するInterceptorは次のようになります。
package examples.aaa.interceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.seasar.framework.aop.interceptors.AbstractInterceptor;
public class MyInterceptor extends AbstractInterceptor{
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("before");
Object ret = invocation.proceed();
System.out.println("after");
return ret;
}
}
クラス名
org.seasar.framework.aop.intertype.PropertyInterType
説明
フィールドに対するgetter / setterメソッドを追加するInterTypeです。
PropertyInterTypeを使うには、S2Tigerが必要です。
注意点
privateのフィールドに対するgetter / setterは作成されません。
フィールドはprotectedにしてください(public でも可)。
<component class="Hoge">
<interType>
<component class="org.seasar.framework.aop.interType.PropertyInterType"/>
</interType>
</component>
PropertyInterTypeを適用するクラスには、getter / setterを追加したいフィールドにPropertyアノテーションを指定します。
import org.seasar.framework.container.annotation.tiger.Property;
import org.seasar.framework.container.annotation.tiger.PropertyType;
public class Hoge {
@Property
protected int foo;
@Property(PropertyType.READ)
protected long bar;
@Property(PropertyType.WRITE)
protected String baz;
}
上の例では、フィールドfooにはgetterとsetterメソッドが、barにはgetterメソッドが、bazにはsetterメソッドが作成されます。
クラスにPropertyアノテーションを指定することもできます。
Propertyアノテーションの指定されていないフィールドへのデフォルトの指定になります。
import org.seasar.framework.container.annotation.tiger.Property;
import org.seasar.framework.container.annotation.tiger.PropertyType;
@Property
public class Hoge {
protected int foo;
protected long bar;
@Property(PropertyType.NONE)
protected String baz;
}
上の例では、フィールドfooとbarにはgetterとsetterメソッドが作成されますが、bazにはメソッドが作成されません。
クラス名
org.seasar.framework.aop.intertye.InterTypeChain
説明
複数のInterTypeをグルーピング化し、再利用しやすくします。複数のInterTypeの組み合わせを複数コンポーネントに適用する場合は、InterTGypeChainで複数のInterTypeを1つにまとめて、各コンポーネントにはInterTypeChainを指定するようにするといいでしょう。
<component name="interType1" .../>
<component name="interType2" .../>
<component name="interType3" .../> <component name="chain" class="org.seasar.framework.aop.interttype.InterTypeChain"> <initMethod name="add"><arg>interType1</arg></initMethod> <initMethod name="add"><arg>interType2</arg></initMethod> <initMethod name="add"><arg>interType3</arg></initMethod> </component>
<component ...>
<interType>chain</interType>
</component>
<component ...>
<interType>chain</interType>
</component>
説明
独自にInterTypeを作成する場合は、次のインターフェースまたは、抽象クラスを実装します。
- org.seasar.framework.aop.InterType
- org.seasar.framework.aop.intertype.AbstractInterType
InterTypeを実装するクラスは、以下のメソッドを実装します。
- public void introduce(Class targetClass, CtClass enhancedClass)
targetClassはInterTypeが適用されるクラスです。enhancedClassはInterTypeを組み込むクラスで、先に登録されているInterceptorやInterTypeが適用済みの場合もあります。
CtClassの詳細はJavassistのチュートリアルやJavaDocを参照してください。
AbstractInterTypeは、InterTypeをimplementsした抽象クラスです。AbstractInterTyeのサブクラスは次のメソッドを実装します。
- public void introduce() trhows CannotCompileException, NotFoundException
AbstractInterTypeのサブクラスは、次のメソッドで必要なオブジェクトを取得することができます。
- protected Class getTargetClass()
- protected CtClass getEnhancedClass()
- protected ClassPool getClassPool()
AbstractInterTypeは、フィールドやメソッド,実装するインタフェースを追加するためのユーティリティメソッドを提供します。以下はその一部です。
- protected void addField(Class type, String name)
- protected void addField(Class type, String name, String init)
- protected void addStaticField(Class type, String name)
- protected void addStaticField(Class type, String name, String init)
- protected void addMethod(String name, String src)
- protected void addMethod(Class returnType, String name, String src)
- protected void addMethod(String name, Class[] paramTypes, String src)
- protected void addMethod(Class returnType, String name, Class[] paramTypes, String src)
- protected void addStaticMethod(String name, String src)
- protected void addStaticMethod(Class returnType, String name, String src)
- protected void addStaticMethod(String name, Class[] paramTypes, String src)
- protected void addStaticMethod(Class returnType, String name, Class[] paramTypes, String src)
|