ログイン
i-mobile
記事の一覧
4.<前の日

2004-04-02 (金)

[][]「MDA導入ガイド」11-12章 01:23

残りあと少しなので,頑張りましょう.

11. OMG標準とその他の技術

本章では,UMLを始めMOF,CWMといったOMGの標準技術について解説しています.

その中で注目はQVT(Query,Views,and Transformations).これは,MOFで定義されたモデル間の変換ルールを定義するというものだそうです.そういうものの標準化が始まっているというだけで,実際にどのようなものになるのかは触れられていなのですが,非常に興味深いです.

12. MDAの展望

MDAによるモデルからのコード生成を,高級言語(手続き型言語)から機械語へのコンパイルに例えて,MDAパラダイムシフトは必然なのだとしています.将来は,現在機械語を意識する人がほとんどいないのと同様,コードさらにはPSMさえも意識されなくなるだろうとのことです.ふーむ.

開発プロセスでは,やはり分析の成果物としてPIMが作られるとのこと.ということは,いずれPSMが意識されなくなれば,設計工程がなくなるということ? 本当かなぁ? 本書を最後まで読んでも,この疑問は解消されませんでした.


ということで,一応読破しました.全体として,とても平易な記述で,これからMDAの学習を始める人には最適なのではないでしょうか.その分,すでに雑誌等でMDAの概要を理解している人が,より深くMDAを理解したいという場合にはもの足りないのではないかと思います.

[][] 「恋するハニカミ!」 00:35

蛯原友里がちょい役で出てたらしい.部屋にいたのに見損ねました.(;_;)

っていうかさぁ,わざわざi-modeで「ザ・テレビジョン」の「スターTVスケジュール」に登録してチェックしてるのにさぁ,役に立ってないじゃん!! なにが「出演する番組はありません」なんだよ! あ,TBSの公式サイトにも名前ないし.まだまだマイナーってことでしょうがないわけか... 無念だ.

[][] Lakers 93 - 85 Rockets 00:26

\(^o^)/

10連勝です.また負けたキングスに並んでしまいました.直接対決では負け越している(1勝2敗)のにレイカーズが地区首位なんですね.なんにせよめでたい!

[][][] Spring Framework 入門記 AOPその5 Pointcutその他 21:22

今回は,Pointcutの仕上げとしてSpringが標準で用意してくれているPointcutの実装クラスについて学習します.

Static pointcut

  • NameMatchMethodPointcut

AOP その2」で使用した,Joinpointのメソッド名でマッチングを行うPointcutです.Advisorインタフェースを実装したNameMatchMethodPointcutAdvisorも用意されています.

このPointcutは,mappedNamesという文字列の配列プロパティを持っています.このプロパティに設定する文字列には,ワイルドカードとして'*'を含めることが出来ます.といっても,先頭または末尾のみ有効なようで,途中に書いても効果はなさそう.無念だ.そういう場合は後述の正規表現を使用するPointcutを使えということでしょうね.

matches(Method, Class)メソッドは,Joinpointのメソッド名がmappedNamesプロパティのいずれかの文字列と一致(ワイルドカード含む場合はマッチ)すればtrueを返します.

  • RegexpMethodPointcut

NameMatchMethodPointcutと同様,Joinpointのメソッド名でマッチングを行うPointcutですが,正規表現を使うことができます.Advisorインタフェースを実装したRegexpMethodPointcutAdvisorも用意されています.

このPointcutは,patternという文字列のプロパティを持っていて,正規表現を設定することが出来ます.正規表現の実装には,Jakarta OROが使用されているようで,たとえJDK1.4で実行する場合でも,java.util.regexは使われないようです.無念だ.OROということでパフォーマンスが気になるところではありますが,このPointcutはStaticであるため,正規表現のマッチングが行われるのはAOP Proxy作成時だけです.あまり神経質になる必要はないかもしれません.

matches(Method, Class)メソッドは,Joinpointのメソッド名が正規表現とマッチすればtrueを返します.

  • RootClassFilter

これはPointcutそのものではなくて,ClassFilterインタフェースの実装です.他のPointcutから利用されることを意図しているのでしょう.コンストラクタでClassを設定することができます.matches(Class>メソッドは,Joinpointのターゲットオブジェクトのクラスが,コンストラクタで渡されたClassに適合する(Class#isAssignableFrom(Class)trueを返す)場合にtrueを返します.


Dynamic pointcut

  • ControlFlowPointcut

AspectJのcflowのようなPointcutで,あるJoinpointが呼び出されている間の全てのJoinpointを採用するというPointcutです.コンストラクタでクラスとメソッド(省略可)を指定することが出来ます.

matches(Method, Class, Object[])は,現在のスタックフレームを調べて,コンストラクタで指定されたクラス・メソッドが含まれている場合にtrueを返します.でもでも,JDK1.3以前のための実装は少し怪しい感じ.メソッド名を省略した場合,クラス名だけでチェックを行うのですが,単純にString#indexOf(String)を使っているので,例えばFooを指定するとFooBarも引っかかってしまうような? JDK1.4以降を使えばいいんですけどね.

スタックフレームを取得してマッチングを行うことから,通常のPointcutよりもかなり遅いので気をつけろとのことです.JDK1.4で5倍くらい,JDK1.3だと10倍以上だとか.

その他

  • ComposablePointcut

複数のPointcutを組み合わせることの出来るPointcutです.組み合わせ方として,Pointcutの和を取るunion,積を取るintersectionを使うことが出来ます.ただし,unionについてはClassFilterおよびMethodMatcherを組み合わせることは出来ますが,Pointcutを組み合わせることは出来ません.そのような場合は,後述のUnionPointcutを使えとのことです.intersectionPointcutも組み合わせることが出来ます.

前回作成したDynamic Pointcutの修正版では,効率を考えてmatches(Method, Class)メソッドとmatches(Method, Class, Object[])の両方を実装しましたが,むしろNameMatchMethodPointcutのようなStatic pointcutとをintersectionして使うほうがSpring流なのかもしれません.

  • UnionPointcut

コンストラクタで設定された二つのPointcutの和を取るPointcutです.

ComposablePointcutともども,Springにしては珍しくプロパティではなくコンストラクタで設定を行います.どちらかというと,定義ファイルに記述して使うよりも,他のPointcutの実装などからプログラマティックに使われることを想定しているのかもしれません.


おおむねRegexpMethodPointcutがあれば困らないような気がするわけですが,あって困るものでもないので機会があればありがたく使わせていただくことにします.

といったところでPointcutは終了にします.


... と思ったのですが,何もコードを書かないのはブログ^h^h^h日記としてどうよ? という気がしたので,とりあえず何かサンプルを作ります.おもしろそうなのはControlFlowPointcutですが,有用そうなのはComposablePointcutだし... そんな場合は両方使ってしまいましょう.うん,その方が素敵(キラッ)!

まずPointcutを作ります.これは,プロパティに設定されたPointcutの配列全てのintersection(積)を取ってくれるようにします.というわけでこんな感じ.

package study;
import org.aopalliance.aop.Advice;
import org.springframework.aop.ClassFilter;
import org.springframework.aop.MethodMatcher;
import org.springframework.aop.Pointcut;
import org.springframework.aop.PointcutAdvisor;
import org.springframework.aop.support.ComposablePointcut;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.Ordered;

public class IntersectionPointcutAdvisor implements InitializingBean , Pointcut, PointcutAdvisor, Ordered {
    private Pointcut[] pointcuts;
    private Advice advice;
    private int order = Integer.MAX_VALUE;
    private ComposablePointcut composablePointcut = new ComposablePointcut();

    //InitializingBean
    public void afterPropertiesSet() {
        if (pointcuts != null) {
            for (int i = 0; i < pointcuts.length; ++i) {
                composablePointcut.intersection(pointcuts[i]);
            }
        }
    }

    //Pointcut
    public ClassFilter getClassFilter() {
        return composablePointcut.getClassFilter();
    }
    public MethodMatcher getMethodMatcher() {
        return composablePointcut.getMethodMatcher();
    }

    //PointcutAdvisor
    public Pointcut getPointcut() {
        return composablePointcut;
    }
    public boolean isPerInstance() {
        throw new UnsupportedOperationException("perInstance property of Advisor is not yet supported in Spring");
    }

    //getters and setters
    public Pointcut[] getPointcuts() {
        return pointcuts;
    }
    public void setPointcuts(Pointcut[] pointcuts) {
        this.pointcuts = pointcuts;
    }
    public Advice getAdvice() {
        return advice;
    }
    public void setAdvice(Advice advice) {
        this.advice = advice;
    }
    public int getOrder() {
        return order;
    }
    public void setOrder(int order) {
        this.order = order;
    }
}

プロパティに設定されたPointcut配列のintersectionを取るためにInitializingBeanimplementsしています.

次に実験用のクラス.今回は,FooBarの二つのクラスを使います.

まずはFoo

package study;

public class Foo {
    private Bar bar;
    public Bar getBar() {
        return bar;
    }
    public void setBar(Bar bar) {
        this.bar = bar;
    }
    public void yoku() {
        System.out.println("よーく");
        kangaeyo();
    }
    public void kangaeyo() {
        System.out.println("考えよー,");
        bar.okaneha();
    }
}

これは,Barへの参照をプロパティで持っています.

次にBar

package study;

public class Bar {
    public void okaneha() {
        System.out.println("お金は");
        daijidayo();
    }
    public void daijidayo() {
        System.out.println("大事だよー.");
    }
}

そして定義ファイルですが,今回はBarの方にAspectをWeavingします.そのAspectのPointcutにはもちろんIntersectionPointcutAdvisorを使います.そのpointcutsプロパティには,RegexpMethodPointcutControlFlowPointcutを設定します.

こんな感じ.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
    <bean id="foo" class="study.Foo">
        <property name="bar"><ref bean="bar"/></property>
    </bean>

    <bean id="barTarget" class="study.Bar">
    </bean>

    <bean id="bar" class="org.springframework.aop.framework.ProxyFactoryBean">
        <property name="target"><ref bean="barTarget"/></property>
        <property name="interceptorNames"><value>advisor</value></property>
    </bean>

    <bean id="advisor" class="study.IntersectionPointcutAdvisor">
        <property name="pointcuts">
            <list>
                <bean class="org.springframework.aop.support.RegexpMethodPointcut">
                    <property name="pattern"><value>.*\.okaneha</value></property>
                </bean>
                <bean class="org.springframework.aop.support.ControlFlowPointcut">
                    <constructor-arg index="0"><value>study.Foo</value></constructor-arg>
                </bean>
            </list>
        </property>
        <property name="advice"><ref bean="interceptor"/></property>
    </bean>

    <bean id="interceptor" class="org.springframework.aop.interceptor.DebugInterceptor">
    </bean>
</beans>

RegexpMethodPointcutpatternプロパティには".*\.okaneha"を指定しています.実はこのPointcut,マッチングの際に使用するメソッド名は,そのクラスの完全限定名で修飾されていたんですね.ということで,任意のクラス(といっても今回の場合は意味がないのですが)のokaneha()にマッチするように正規表現を指定しました.

ControlFlowPointcutについては,引数が1つのコンストラクタで初期化するようにしています.この場合の引数はClassですので,このPointcutはスタックフレーム中にstudy.Fooが含まれていればマッチすることになります.

この2つのPointcutのIntersectionが,Barに適用されるPointcutということになります.

最後に実行用のクラス.

package study;
import org.springframework.beans.factory.access.BeanFactoryLocator;
import org.springframework.beans.factory.access.BeanFactoryReference;
import org.springframework.context.ApplicationContext;
import org.springframework.context.access.ContextSingletonBeanFactoryLocator;

public class Main {
    public static void main(String[] args) {
        try {
            BeanFactoryLocator locator = ContextSingletonBeanFactoryLocator.getInstance();
            BeanFactoryReference ref = locator.useBeanFactory("context");
            ApplicationContext context = (ApplicationContext) ref.getFactory();

            Foo foo = (Foo) context.getBean("foo");
            foo.yoku();
            Bar bar = (Bar) context.getBean("bar");
            bar.okaneha();

            ref.release();
        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }
}

そして実行!!!

よーく
考えよー,
Debug interceptor: count=1 invocation=[Invocation: method=[public void study.Bar.okaneha()] args=[Ljava.lang.Object;@1556d12] target is of class study.Bar]
お金は
大事だよー.
Debug interceptor: next returned
お金は
大事だよー.

このように,Fooを経由して呼び出された場合のBar#okaneha()にはAspectが適用されて前後にトレースが出力されています.しかし,Fooを介さずにMain#main()から呼び出された場合にはAspectが適用されていません.ということで,少なくともControlFlowPointcutが効いていることが確認できました.RegexpMethodPointcutの方は,今回の例ではあってもなくても同じ? 心より恥じる.


それにしても,やっぱりこういうものは動かしてみないと分からないことが多々ありますね.今回,実は2つの点ではまりました.無念だ.

一つ目は,すでに書いたようにRegexpMethodPointcutpatternプロパティの指定の仕方です.てっきりメソッド名だけをパターンでマッチングするのだと思ってしまったんですよね.なぜって言われると困るのですが.ということなので,メソッド名に限らずクラス名の部分にも正規表現でフィルタリングすることが出来ます.Springの場合,PointcutもひとつのBeanであり,様々なターゲットに同じPointcutを適用できるので,これは重要なことなのかもしれません.

もうひとつはまってしまったことは,Aspectが適用されるのは,AOP Proxyを経由したメソッド呼び出しの場合だけということです.当然ですよね.でもはまっちゃいました.心より恥じる.今回テスト用に作ったFooBarは,意味もなく自分のクラス(インスタンス)のメソッドを呼び出しています.この場合には,AOP Proxyを経由しないため,Aspectは適用されないんですね.このことになかなか気づくことが出来ませんでした.これって,意外と痛い制約にならないのでしょうか? ちょっとドキドキです.


ということで,今度こそ本当にPointcut終了です.次回からはAdviceです.

[] お仕事スタイル 19:27

  • こげ茶のシャツブルゾン(EZ BY ZEGNA)
  • ベージュのニット(allegri)
  • オフホワイトのコットンパンツ(HELMUT LANG)
  • こげ茶のスエードのチャッカブーツ(Yanko)

自分には珍しい茶系のコーディネートです.ニットには肩のところにこげ茶が入っていて,ベルトもこげ茶のスエードのもの.ベージュのニットとオフホワイトのパンツだとパジャマっぽい感じなのを,肩・腰・足元のこげ茶で引き締めている... つもりなのですが,やっぱりパジャマかも.心より恥じる.

higayasuo ●2004/04/03 10:09
Aspectの適用されたメソッドから自分のメソッドを呼び出した場合、そのメソッドもPointcutで指定されていれば、Aspectはそのメソッドにも(たぶん)適用されると思います。ちょっと混乱しました。文意を取り違えているかも。
koichik ●2004/04/03 11:11
うーん,Springではやっぱり適用されませんね.Seasarでは適用されるんですか? から騒ぎで解説お願いします.
higayasuo ●2004/04/03 12:10
それなら確かにかなり痛い制約。S2は大丈夫だと思いますが、この後、試して日記に書きますね。疑問はすぐに解決しましょう。
higayasuo ●2004/04/03 12:23
思い出しました。S2は大丈夫です。DateのgetTime,toStringをPointcutで指定して、toStringを呼び出したとき、toStringから呼び出されているgetTimeにもAspectは適用されていました。
koichik ●2004/04/03 12:25
すばらしい! これはいいアピールになりますね.(^^;
コメントを書くには、なぞなぞ認証に回答する必要があります。
4.<前の日
●ウェブ検索●