2010年9月10日金曜日

「Javaフレームワーク開発入門」を読んで 総評



読み終わりました。
まず第一に、かなりの良本ですね。
書籍の構成もちゃんとしているし、実装例もわかりやすい。

読者対象としてはjavaの基本を一通り学んで、フレームワークを使った
実践経験がある人ならかなり有用だと思います。
フレームワークの中身ってどうなっているんだろうと興味をもった方が、
OSSフレームワークのソースを読む前にも。

WEBアプリケーション開発において非機能用件、横断的関心事というと、
・エラー処理
・メッセージ処理
・ログ出力処理
・DB処理(ORマップ、トランザクション、データソース管理、排他制御、自動採番)
・ファイル管理処理
・セキュリティ
・帳票出力処理(PDF,CSV)
・外部システム連携
・バッチ制御処理
・権限・ワークフロー(業務より)
・メール
・多言語対応
・数値演算
・日付時刻
・文字コード
・画面部品

ぱっと思いつくだけで結構あるが、大規模アプリケーションなんかだと、
フレームワークの上に共通基盤、その上に業務APをのせるといった
構成の方が効率がよい。
共通基盤を設計しようと思った場合に、インターフェース・拡張ポイント等
迷うことが多々あると思うが、そういった共通基盤を作成する人なんかも
良い指針になる本だと思います。

また、リフレクションAPIを細かく解説していたり、
デザインパターンをいくつか紹介しています。

デザインパターンの説明は、Gofで紹介する23パターン全て
ではなく、フレームワーク作りでよく使うパターンのみだが、
どの本よりわかりやすく感じました。
Adapterパターン、Proxyパターン、Decoratorパターンなんかは
混同しやすいけど、その違いなんかも説明しています。

説明しているデザインパターン
・Template Methodパターン
・Flyweightパターン
・Factory Methodパターン
・Decoratorパターン
・Adapterパターン
・Proxyパターン
・Singletonパターン
・Intercepting Filterパターン


あとは、3人の登場人物が会話してプロジェクトを進めていくという、
よく海外本にあるような遊び心ある構成が程よい息抜きによかったです。

2010年9月9日木曜日

「Javaフレームワーク開発入門」を読んで4



▼実装例で気になったイディオム

例外をStringに変換するメソッド
public static String toString(Throwable t) {
    StringWriter sw = new StringWriter();
    t.printStackTrace(new PrintWriter(sw));
    return sw.toString();
}

こんなインターフェースあるのね。いつもStackTraceElement[] traces = t.getStackTrace();してt.getCause()してループで回すなんて関数つくってた。

2010年9月7日火曜日

「Javaフレームワーク開発入門」を読んで3




▼AOPのプロダクト比較

・AOPのウィービング(インターセプタ組み込み)のタイミングはプロダクトによって違う
     
  • AspectJ     Compile-time weaving, load-time weaving
  •  
  • Seasar2     run-time weavng
  •  
  • SamuraiAOP  load-time weaving


・ウィービングのタイミングによる考慮点
  • Compile-time weaving
  •  ・コンパイルするときにソースコードが必要なため、jarファイルのようなモジュールに対してはAOPの適用が難しい  ・コードを変更するたびに特殊なコンパイルが必要
  • run-time weaving
  • ・特定のAPIに依存する   Seasar2の場合だとS2コンテナから取得したオブジェクトしかAOPがかからない   S2Container、S2ContainerFactory等に依存 ・クラスが大量に生成される(permanent領域が足りなくなる可能性も)
  • load-time weaving
  • ・VMオプションが必要→GAEのようなVMオプションを設定できない環境は厳しい


・言語の違い
     
  • AspectJ     Java, AspectJ言語
  •  
  • Seasar2     Java, XML
  •  
  • SamuraiAOP  Java, XML


・ポイントカット指定の違い
     
  • AspectJ     アスペクトに定義
  •  
  • Seasar2     diconに定義
  •  
  • SamuraiAOP  XMLに定義


・ジョインポイントの違い
                                                                                                                                                                                                                                                                                                   
プロダクトインスタンスメソッドprivateメソッドstaticメソッドfinalメソッドコンストラクタフィールドアクセス
AspectJ
Seasar2×××××
SamuraiAOP×



それぞれメリット・ディメリットがありますが、設定のしやすさ/学習コストは
Seasar2→SamuraiAOP→AspectJ、機能面ではAspectJ→SamuraiAOP→Seasar2という印象。
実際のプロジェクトではSeasar2のAOPしか使ったことないですが、
privateにAOPをかけることはほとんどなかったので特に困らなかったです。
DIコンテナを使用する場合は、それに付属するAOP機能を使用するのが無難な気がします。


・AOPの標準化使仕様

AOP Alliance(AOP共通アーキテクチャの作成/標準化団体)を利用しているプロダクト

(org.aopalliance.interceptパッケージ)

 Seasar2, Spring, Guice, SamuraiAOP


javaEEを利用しているプロダクト

(javax.interceptorパッケージ)

 EJB3, Seam, SamuraiAOP

「Javaフレームワーク開発入門」を読んで2



▼参照の種類
java.util.WeakHashMapを利用すると、キーへの参照がなくなった場合、キャッシュしていたオブジェクトはGCによって改修される。

参照の種類
・弱参照          java.lang.ref.WeakReference    GCが起きるとほぼ必ず切れる参照
・ソフト参照      java.lang.ref.SoftReference    ヒープ領域が足りなくなると切れる参照
・ファントム参照  java.lang.ref.PhantomReference あるオブジェクトがいつGCされたのかを知りたいときに使う参照
・強参照                                         通常の参照



ここが参考になりますね。「Javaのメモリ管理」
http://blogs.wankuma.com/nagise/archive/2007/07/29/87593.aspx

「Javaフレームワーク開発入門」を読んで1

「Javaフレームワーク開発入門」という本を電車などでちょろちょろ読んでいるので気になったところをメモっていきます。


3-2-2 Flyweightパターン

▼IntegerクラスはvalueOfメソッドを利用した場合、-128<=value<=127の範囲でキャッシュするようにしている。
テストコード
public class IntegerTest {

    /**
     * コンストラクタ。
     */
    public IntegerTest() {

    }

    public static void main(String[] args) {
        Integer i1 = new Integer(10);
        Integer i2 = new Integer(10);
        compare(i1, i2);
        
        i1 = Integer.valueOf(127);
        i2 = Integer.valueOf(127);
        compare(i1, i2);
        
        i1 = Integer.valueOf(128);
        i2 = Integer.valueOf(128);
        compare(i1, i2);
        
        i1 = Integer.valueOf(-128);
        i2 = Integer.valueOf(-128);
        compare(i1, i2);
        
        i1 = Integer.valueOf(-129);
        i2 = Integer.valueOf(-129);
        compare(i1, i2);
        
    }
    
    private static void compare(Integer i1, Integer i2) {
        if (i1 == i2) {
            System.out.println("i1 == i2");
        } else {
            System.out.println("i1 != i2");
        }
    }
}


実行結果 
i1 != i2
i1 == i2
i1 != i2
i1 == i2
i1 != i2

おおっほんとですね。

2010年9月6日月曜日

ToStringBuilderを使用したtoString実装

Apache Commons LangにtoStringを簡単に実装するためのクラスToStringBuilderというのがあったので使ってみた(commons-lang-2.1.jar使用)。

Beanクラス(toString実装クラス)
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;

public class CommonLangTestBean {

    private String aaa;

    private String bbb;

    private String ccc;

    private String ddd;

    private String eee;

    private String fff[] = {"fff0", "fff1", "fff2"};
    
    /**
     * コンストラクタ。
     */
    public CommonLangTestBean() {

    }

    /**
     * aaa を取得します。
     *
     * @return aaa
     */
    public String getAaa() {
        return aaa;
    }

    /**
     * aaa を設定します。
     *
     * @param aaa 設定する aaa
     */
    public void setAaa(String aaa) {
        this.aaa = aaa;
    }

    /**
     * bbb を取得します。
     *
     * @return bbb
     */
    public String getBbb() {
        return bbb;
    }

    /**
     * bbb を設定します。
     *
     * @param bbb 設定する bbb
     */
    public void setBbb(String bbb) {
        this.bbb = bbb;
    }

    /**
     * ccc を取得します。
     *
     * @return ccc
     */
    public String getCcc() {
        return ccc;
    }

    /**
     * ccc を設定します。
     *
     * @param ccc 設定する ccc
     */
    public void setCcc(String ccc) {
        this.ccc = ccc;
    }

    /**
     * ddd を取得します。
     *
     * @return ddd
     */
    public String getDdd() {
        return ddd;
    }

    /**
     * ddd を設定します。
     *
     * @param ddd 設定する ddd
     */
    public void setDdd(String ddd) {
        this.ddd = ddd;
    }

    /**
     * eee を取得します。
     *
     * @return eee
     */
    public String getEee() {
        return eee;
    }

    /**
     * eee を設定します。
     *
     * @param eee 設定する eee
     */
    public void setEee(String eee) {
        this.eee = eee;
    }
    
    @Override
    public String toString() {
        return ToStringBuilder.reflectionToString(this, ToStringStyle.DEFAULT_STYLE);
    }
}



実行クラス
public class CommonLangTest {

    /**
     * コンストラクタ。
     */
    public CommonLangTest() {

    }

    public static void main(String[] args) {
        CommonLangTestBean cltb = new CommonLangTestBean();
        cltb.setAaa("aaahoge");
        cltb.setBbb("bbbhoge");
        cltb.setCcc("ccchoge");
        System.out.println(cltb.toString());
    }
}


実行結果
ommonLangTestBean@b2fd8f[aaa=aaahoge,bbb=bbbhoge,ccc=ccchoge,ddd=<null>,eee=<null>,fff={fff0,fff1,fff2}]


スタイル指定を変更(CommonLangTestBean.java)
@Override
public String toString() {
    return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE);
}


実行結果 これが一番見やすいかな
CommonLangTestBean@b2fd8f[
  aaa=aaahoge
  bbb=bbbhoge
  ccc=ccchoge
  ddd=<null>
  eee=<null>
  fff={fff1,fff2,fff3}
]


リフレクション使えばできると思うけど、ライブラリとして用意されているので使う価値ありそうですね。toStringを実装しておくとデバッグの時も何かと便利だし。

アノテーションはオーバライドしたメソッドでも有効なのか

親クラスのメソッドに定義したアノテーションが、継承した子クラスでオーバライドしても有効なのか(メタプログラミングで取得可能か)気になったので試してみた。


アノテーションクラス
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Inherited
@Retention(RetentionPolicy.RUNTIME)
public @interface A {

}


親クラス
@A
public class ParentClass {

    public ParentClass() {}

    @A
    public void hoge() {
        System.out.println("parent hoge");
    }
}


子クラス
public class ChildClass extends ParentClass {

    public ChildClass() {}
   
    public void hoge() {
        System.out.println("child hoge");
    }
}


実行クラス
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

public class AnnotationTest {

    public AnnotationTest() {}

    public static void main(String args[]) throws Exception {
        Class clazz = ChildClass.class;

        //クラスのアノテーション取得
        Annotation[] anns = clazz.getAnnotations();
        for (Annotation a : anns) {
            System.out.println("class:  " + a.annotationType());
        }

        // メソッドのアノテーション取得
        Method m = clazz.getMethod("hoge");
        anns = m.getAnnotations();
        for (Annotation a : anns) {
            System.out.println("method:  " + a.annotationType());
        }

    }
}


実行結果
class:  interface A



クラスのアノテーションは取得可能でオーバライドしたメソッドは取得不可でした。
まぁオーバライドしたら子クラスのメソッドでクラスが構築されるのだから当然といえば当然ですな。
オーバライドしなければもちろんメソッドも取得可能です。
ちなみにアノテーションクラスに@Inheritedをつけないとクラスのアノテーション取得不可ですね。