| S2AOPの概要 AOPを考える上でキーとなる概念 S2AOPリファレンス S2AOPで用意している主なInterceptor TraceInterceptor ThrowsInterceptor ToStringInterceptor RemoveSessionInterceptor InvalidateSessionInterceptor DependencyLookupInterceptor InterceptorChain InterceptorLifecycleAdapter 独自実装によるInterceptor S2AOPで用意している主なInterType PropertyInterType InterTypeChain 独自実装によるInterType ## S2AOPの概要 AOPとはAspect Oriented Programmingの略で、 複数のクラスに分散するロジックをモジュールとして抽出し、 外側から織り込む手法です。 例えば、ログ出力の機能を考えてみてください。 ログ出力の処理を複数のクラスに同じように記述するのは、 面倒なだけでなく、ログ出力の処理に仕様変更が入った場合に、 複数のクラスを同じように修正しなければいけないという問題がおきます。 つまり、仕様変更に弱いのです。 このような場合に、ログ出力の処理をモジュールとして抽出し、 個々のクラスからは削除します。 そして、コンパイル時もしくは実行時に抽出したモジュールをバイトコードに埋め込むことで、 あたかもソースコードに記述されているかのように実行することができます。 ログ出力の処理に仕様変更が入った場合も抽出したモジュールを修正するだけですみます。 メンテナンス性が向上することがわかっていただけるでしょう。 ### AOPを考える上でキーとなる概念 #### Advice(MethodInterceptor) プログラム中に挿入されるコードを表します。Interceptorと呼ばれることもあります。 #### Joinpoint(MethodInvocation) 対象となるクラスとAdviceを結合するポイントを表します。 AdviceはJoinpointから引数やメソッドの情報を取得することができます。 #### Pointcut どこにJoinpointを設定するのかを定義します。 #### Aspect AdviceとPointcutを関連付けます。 #### InterType フィールドやメソッドの追加、実装するインタフェースの追加など，クラスの静的な構造を変更します。 ## S2AOPリファレンス ### S2AOPで用意している主なInterceptor #### TraceInterceptor ##### クラス名 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>
#### ThrowsInterceptor ##### クラス名 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;
        }
    }
#### ToStringInterceptor ##### クラス名 org.seasar.framework.aop.interceptors.ToStringInterceptor ##### 説明 toString()メソッドでフィールドの情報を出力するためのInterceptorです。 #### RemoveSessionInterceptor ##### クラス名 org.seasar.framework.aop.interceptors.RemoveSessionInterceptor ##### 説明 セッションに格納されているオブジェクトを、メソッドが正常に終了した(例外が発生しなかった)場合に、 自動的に削除するためのInterceptorです。 メソッドにRemoveSessionアノテーションを指定して使います。 次の例では、hoge()メソッドの呼び出しが正常終了した場合に、 セッションに格納されているfooオブジェクトを削除します。
    @RemoveSession("foo")
    public void hoge() {
        ...
    }
#### InvalidateSessionInterceptor ##### クラス名 org.seasar.framework.aop.interceptors.InvalidateSessionInterceptor ##### 説明 セッションを、メソッドが正常に終了した(例外が発生しなかった)場合に、 自動的に破棄するためのInterceptorです。 メソッドにInvalidateSessionアノテーションを指定して使います。 次の例では、hoge()メソッドの呼び出しが正常終了した場合に、 HTTPセッションを破棄します。実際には、セッションの破棄はS2Containerの提供するServlet Filter (S2ContainerFilter) によって行われます。
    @InvalidateSession
    public void hoge() {
        ...
    }
#### DependencyLookupInterceptor ##### クラス名 org.seasar.framework.aop.interceptors.DependencyLookupInterceptor ##### 説明 getterメソッドに適用されて、 S2コンテナからルックアップしたコンポーネントを返すインターセプタです。 次の例では、getMyService()メソッドを呼び出すとS2コンテナからルックアップされたMyServiceが返されます。
    @DependencyLookup
    public MyService getMyService() {
        return null;
    }
#### InterceptorChain ##### クラス名 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>
#### InterceptorLifecycleAdapter ##### クラス名 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 #### 説明 独自にInterceptorを作成する場合は、次のインターフェースまたは、抽象クラスを実装します。 org.aopalliance.intercept.MethodInterceptor org.seasar.framework.aop.interceptors.AbstractInterceptor どちらの場合も実装するメソッドは、以下のinvoke()メソッドの１つだけです。 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;
        }
    }
### S2AOPで用意している主なInterType #### PropertyInterType ##### クラス名 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にはメソッドが作成されません。 #### InterTypeChain ##### クラス名 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 #### 説明 独自に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) |
| Copyright© 2004-2005, The Seasar Foundation and the others. All rights reserved.