Page List

Search on the blog

2012年8月28日火曜日

Spring Framework -オブジェクトの生成-

Spring Frameworkについて、基本的な機能を簡単に紹介します。
  1. オブジェクトの生成
  2. Dependency Injection
  3. Aspect Oriented Programming
の3つの機能を3回のpostに分けて書きます。まずは、オブジェクトの生成から書きます。

XML設定ファイルを利用したオブジェクトの生成
// src/cc/co/goodpreparations/Main.java 

package cc.co.goodpreparations;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Main {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
        
        Person person =  (Person)context.getBean("person");

        person.saySomething();
    }
}
// src/cc/co/goodpreparations/Person.java

package cc.co.goodpreparations;

public class Person {
    private String message;

       public void setMessage(String message){
          this.message  = message;
       }

       public void saySomething(){
          System.out.println(message);
       }
}
<?xml version="1.0" encoding="UTF-8"?>
<!-- src/Beans.xml -->

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

   <bean id="person" class="cc.co.goodpreparations.Person">
       <property name="message" value="Hello!"/>
   </bean>
</beans>
XMLファイルにBeanのidとクラスのマッピングを記述します。使用者はidを指定して対応するクラスのオブジェクトを生成します。普通にnewすればいいんじゃない?と思う人もいるかもしれませんが、上記のようにSpringが提供するコンテナからオブジェクトを生成することで、DI/AOPといった機能が使えるようになります。

フィールド値の設定
オブジェクトを生成するときにフィールドの初期値を設定出来ます。同一のクラスから生成されているがフィールド初期値が異なるインスタンスは、異なるBean idをつけることで区別できます。XMLのproperty要素内でフィールドの設定をしていますが、ここで設定するフィールドには必ずsetter(この例の場合はPerson#setMessage)を定義しなければいけません。(JavaBeansなので当然ですが。)
// src/cc/co/goodpreparations/Main.java
package cc.co.goodpreparations;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Main {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
        
        Person taro =  (Person)context.getBean("taro");
        taro.saySomething();
        
        Person hanako =  (Person)context.getBean("hanako");
        hanako.saySomething();
        
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<!-- src/Beans.xml -->

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

   <bean id="taro" class="cc.co.goodpreparations.Person">
       <property name="message" value="ぼく太郎!"/>
   </bean>
   <bean id="hanako" class="cc.co.goodpreparations.Person">
       <property name="message" value="わたし花子!"/>
   </bean>
</beans>
と、このように太郎くんと花子さんを作れます。

Beanのスコープ
Beanを生成するときに、そのスコープを設定することができます。
  1. singleton
  2. prototype
  3. request
  4. session
  5. global-session
3.-5.はWebアプリケーションに特化したものなので、ここでは1.と2.のみを説明します。まずはsingleton
// src/cc/co/goodpreparations/Main.java
package cc.co.goodpreparations;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Main {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
        
        Person person = (Person)context.getBean("person");
        person.setMessage("Goodbye!");
        person.saySomething();
        
        Person person2 = (Person)context.getBean("person");
        person2.saySomething();
        
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<!-- src/Beans.xml -->

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

   <bean id="person" class="cc.co.goodpreparations.Person" scope="singleton">
       <property name="message" value="Hello!"/>
   </bean>
</beans>
scope="singleton"のところに注目です。名前から想像がつくように、scopeをsingletonにすると同一のidを持つBeanはアプリケーション上で一つしか作られません。つまり、context#getBeanは毎回同じインスタンスの参照を返します。実行結果は
>Goodbye!
>Goodbye!
となります。ちなみにデフォルトのスコープはsingletonです。scope属性を明記しなかった場合、そのBeanのスコープはsingletonになります。
次に、prototypeを試してみます。先ほどと同様の例でscope属性のみをprototypeに変更すると、実行結果は
>Goodbye!
>Hello!
になります。スコープをprototypeにすると、毎回異なるインスタンスが生成されます。

コールバック関数の指定
Beanが生成されたとき/破棄されるときに、何か処理をしたい場合はコールバック関数を指定することができます。
// src/cc/co/goodpreparations/Main.java
package cc.co.goodpreparations;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Main {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
        
        Person person = (Person)context.getBean("person");
        person.saySomething();
        person = null;
         ((AbstractApplicationContext) context).registerShutdownHook();
    }
}
// src/cc/co/goodpreparations/Person.java
package cc.co.goodpreparations;

public class Person {
    private String message;

       public void setMessage(String message){
          this.message  = message;
       }

       public void saySomething(){
          System.out.println(message);
       }
       
       public void initFunc() {
           System.out.println("A Person Bean is created!");
       }

       public void destroyFunc() {
           System.out.println("A Person Bean is destroyed!");
       }
}
<?xml version="1.0" encoding="UTF-8"?>
<!-- src/Beans.xml -->

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

   <bean id="person" class="cc.co.goodpreparations.Person" scope="singleton"
            init-method="initFunc" destroy-method="destroyFunc">
       <property name="message" value="Hello!"/>
   </bean>
</beans>
XMLファイルのbean要素のinit-method属性、destroy-method属性にて、コールバックしたい関数を指定することができます。これは便利です。mainメソッド内でAbstractApplicationContext#registerShutdownHookを呼んでいますが、これを呼ぶことで確実にBeanが破棄されdestroy-methodで指定した関数が呼ばれるようにしています。


2012年8月26日日曜日

デザインパターン(6) Prototype

まえおき
Prototypeパターンの勉強をしました。書籍だけで大まかなイメージは掴めましたが、「複雑な過程を経てインスタンス生成されるものを簡単に作れる」という例があると、より分かりやすいと思います。


まとめ
  • プロトタイプと呼ばれるオブジェクトをコピーすることで、複雑な過程を経てインスタンス化されるオブジェクトの生成を簡単にすることができる。
  • コピーされたオブジェクトは、プロトタイプとは独立しているので、必要に応じてフィールドの内容を変更することができる。(参考サイト[2,3])
疑問点
  • 書籍には「複雑な過程を経てインスタンス生成されるものを簡単に作れる」という例が無くて具体的なイメージが湧かなかった。参考サイト[1]を見て複雑な過程(もしくは時間のかかる処理)を経て作られるインスタンスのイメージが掴めた。

その他
  • cloneメソッドとCloneableインターフェースに関して学んだ。cloneメソッドはshallow copyなので対象オブジェクトに参照型のフィールドが存在する場合は本当にshallow copyでよいのか注意する。
参考サイト
  1. TECHSCORE
  2. THE CODE PROJECT
  3. javapapers

2012年8月22日水曜日

Ubuntu12.04のキーボード設定


"Sunset on Beach Stage"

キーボードの設定を変えました。

HUDの無効化
デフォルトでは、Altキーを押すとHUDが立ち上がります。Altキーを押す度にウィンドウが開いてフォーカスが移り面倒なので、このサイトを参考にHUDを無効化しました。

右Altキーの設定
やっぱり右Altキーは欲しいです。ということで、以下の手順で変換キーを右Altキーに割り当てました。
  1. コマンドラインにxevと入力する。
  2. 変換キーを押すと、変換キーのkeycode(100)が表示される。
  3. ~/.Xmodmapに以下を設定
keycode 100 = Alt_L
add mod1 = Alt_L

2012年8月17日金曜日

GETとPOSTの違い

GETとPOSTの違いについて勉強しました。

HTML specificationsによる定義/推奨
■ GET
  • データはURLに含まれる
  •  idempotentな(永続的な効果をもたらさない、副作用をもたらさない)処理を行うときに使うことが推奨されている。 ⇒データを取得するときに使用する。

■ POST
  • データはmessage body部分に含まれる。 
  • idempotentではない処理を行うときに使うことが推奨されている。 ⇒データのソート、更新、商品の注文、Emailの送信など

実用的な違い/留意点
  • GETはサーチエンジンのクローラーに踏まれる可能性があるので、副作用のある処理をGETで処理すると、不用意にデータを消去されたり、更新されたりする可能性がある。
  • GETリクエストに対するレスポンスはキャッシュできる)場合が多い。POSTリクエストに対するレスポンスがキャッシュされることはほとんどない。
  • GETはURLをブックマーク保存できる
  • GETはURLにデータが載るので、Webサーバやプロキシサーバーのログに残る。リンクで他ページに遷移したときにRefererのところにも載る。⇒パスワードなどのセンシティブな情報を送る場合はGETは避けるべき。
  • GETにはASCII文字以外を含めない方がいい。(原則上は扱えないが、実用上は扱える。)マルチバイト文字をクエリーに含む検索処理の場合は、POSTを使う方が(idempotent=GETの基本精神に反するが)ベター。
  • GETはPOSTより送信できる情報量が少ない
  • ブラウザの「戻る」ボタン⇒POSTは警告を上げるGETはそのまま遷移
(※)ちなみにキャッシュはいろいろな種類があって、
  • ブラウザーキャッシュ
  • プロキシーキャッシュ
  • ゲートウェイキャッシュ(リバースプロキシー)
などがあります。


まとめ
基本的には、データのREAD処理の場合はGETを使い、CREATE/UPDATE/DELETE処理の場合POSTを使えばよいと思います。あとはセキュリティの観点からセンシティブな情報を送信する場合はPOSTを使うべきです。

参考サイト
  1. Methods GET and POST in HTML forms - what's the difference?
  2. Get vs Post
  3. CACHING TUTORIAL

2012年8月11日土曜日

Reading Java RunTime Source Code (3)

java.util.Stackのソースを読みました。実装は非常にシンプルで分かりやすかったです。気になったところだけ以下にまとめます。

class Stack<E> extends Vector<E>
Eはジェネリクスの型変数の宣言。クラス宣言部を見て分かるように、StackはVectorを継承しています。

synchronized
Stackでは以下のメソッドが定義されています。
  • push
  • pop
  • peek
  • empty
  • search
Stackから連想する処理は一通り実装されています。気になったのは、synchronized。赤字のメソッドのみsynchronized句が指定されています。synchronizedする/しないの違いが気になったので、考えてみました。

public synchronized E pop() {
    E obj;
    int len = size();
    
    obj = peek();
    removeElementAt(len - 1);

    return obj;
}

public synchronized E peek() {
    int len = size();

    if (len == 0)
        throw new EmptyStackException();
    
    return elementAt(len - 1);
}

まずpopですが、3行目と6行目の間で別のスレッドがpopを実行した場合に、ArrayIndexOutOfBoundsExceptionが発生する可能性があります。これを防止するためにオブジェクトにロックをかけていると考えられます。同様にpeekの場合も2行目と7行目の間に別スレッドからpopを実行されるとArrayIndexOutOfBoundsExceptionが発生する可能性があります。

searchは少し違います。ArrayIndexOutOfBoundsExceptionがthrowされそうな箇所は見当たりません。
public synchronized int search(Object o) {
    int i = lastIndexOf(o);
    
    if (i >= 0) {
        return size() - i;
    }
    return -1;
}
searchの仕様は、対象のオブジェクトがStack内に存在すればそのindexを1-basedで返します。存在しなければ-1を返します。もし、2行目と5行目の間にpopが別スレッドから実行されると、仕様と異なる値(0, -2, -3, ..)が返される可能性があります。これを防止するためにsynchronizedを設定していると考えられます。ただし、pushにはsynchronizedが指定されていないので、searchの実行中に別スレッドからpushが実行される可能性はあります。(スレッドがオブジェクトのロックを気にするのは、synchronizedブロックを実行しようとする場合のみなので。)しかし、これは返されるindexが1インクリメントされるだけなので問題はないです。

synchronizedされていないpush、emptyについては上記で見てきたような問題とは無関係ですし、特に他に同期させるべき場面も思い浮かばないので、無くてよいのかなぁという感じです。簡単に必要ないと言いましたが、本来は、他の処理から割り込ませないような場面がないことと、他のsynchronizedが付いている処理を邪魔する可能性がないことを保証した上で、synchronizedは付けなくていいという結論を出さないといけないんですよね。マルチスレッドを考慮したクラス設計は難しいですね。。

2012年8月7日火曜日

Reading Java RunTime Source Code (2)

java.lang.Booleanのソースを読みました。おもしろかったところだけ簡単にまとめておきます。

getPrimitiveClass
Class<Boolean> TYPE = Class.getPrimitiveClass("boolean");
でbooleanのラッパークラスのClassインスタンスを取得します。 Class.getPrimitiveClassメソッドの定義を見ると、以下のようにnative修飾子がついています。
static native Class getPrimitiveClass(String name);
native修飾子は、そのメソッドの実装が Java 以外の言語で記述されてコンパイルされていることを示します。ということで現段階で深堀りするのはやめておきます。

serialVersionID
シリアライズするときに使うもの。シリアライズしたオブジェクトをreadしようとしたとき、 クラスの仕様が変更されていたら不都合があるので、この番号でクラスの仕様が等しいことを確認するようです(http://www.mkyong.com/java-best-practices/understand-the-serialversionuid/)。

hashCode
これはもともとObjectクラスで定義されており、Booleanクラスでオーバーライドされています。 何のために使うのかというと、
Returns a hash code value for the object. This method is
supported for the benefit of hash tables such as those provided by java.util.HashMap(コメントより抜粋)
らしいです。

getBoolean
System.getProperty(property_name) で取得したプロパティ値をBooleanにキャストして返します。
プロパティはこんなのがあるらしいです。
http://docstore.mik.ua/orelly/java/fclass/ch10_02.htm 

上記のページに載っているプロパティを見てもいまいち使い方が分からなかったので、値がtrueになるプロパティがもともと定義されているかどうか以下のコードを書いて調べました。
public class Main {
 public static void main(String[] args) {
  Properties propaties = System.getProperties();
  Set<Entry<Object, Object>> pset = propaties.entrySet();
  for (Entry<Object, Object> entry : pset) {
   String pkey = (String)entry.getKey();
   String pvalue = (String)entry.getValue();
   if ("true".equalsIgnoreCase(pvalue))
    System.out.println(pkey);
  }  
 }
}
無かったです。。おそらく開発者がアプリ上で設定した値の真偽を調べるために使われるものだと考えられます。こんな風に。
public class Main {
 public static void main(String[] args) {
  System.setProperty("logined", "true");
  System.setProperty("network-connected", "true");
  
  System.out.println(Boolean.getBoolean("logined"));
  System.out.println(Boolean.getBoolean("network-connected"));
 }
}

2012年8月5日日曜日

デザインパターン(5) Singleton


まえおき
Singletonです。説明が分かりやすく、かつ、例題もどのような場面で使うのかをしっかり抑えている内容だったため簡単に理解できました。


まとめ
  • そのクラスのインスタンスがシステム上で1個しか存在しないことを保証する。
  • コンピュータそのものを表現したクラス、システム設定を表現したクラス、ウインドウシステムを表現したクラスなどが使用対象となる。

疑問点
  • 特になし

その他
  • コンストラクタをprivateにするというのは大事なポイント。意図を理解していない開発者に対象オブジェクトを普通にnewされると困ったことになってしまうので。
  • static フィールドが初期化されるタイミングも重要。
  • マルチスレッドに関する問題がおもしろかった。synchronizedについて勉強しなおした。