Google Guice(その1) 概要

以前同僚のM君より存在を教えてもらったGoogleのDIコンテナGuiceですが、めでたく1.0になったようなのでちょっと見てました。
一言で言うと、「アノテーションジェネリクスを使い、パフォーマンスを重視し、DIに特化したDIコンテナ」のようです。

とりあえず、「何で新しくDIコンテナ作ったの?」「Springとの違いは?」というのが万人共通の疑問だと思うので、まさにそれに答えているページをまず見てみました。

http://code.google.com/p/google-guice/wiki/SpringComparison
より。記述順序や訳はかなりいい加減なので、ちゃんと読みたい方は上記URLを参照下さい。

  • 発音:「ジュース」*1
  • Springについて
    • SpringによってDIがメジャーになった。Springが無かったらGuiceは無かったかも(少なくとももっと遅かった)
    • Springと直接競合しない。Springは幅広いが、GuiceはDIに特化している
    • GuiceチームはSpringの開発者やコミュニティにかなり世話になった。もっと一緒にやりたいね
    • GuiceはSpringとの統合手段もあり、既存のSpringのBeanをバインドできる。また、AOP Allianceのインターセプタに対応しているから、Springのトランザクションインターセプタも使える
  • Guice全般
    • GuiceGoogle最大のアプリ、AdWordsで使う為に生まれた
    • Guiceアノテーションジェネリクスを取り入れている。おかげで手軽な上、間違いやすくてリファクタリングし辛い文字列による識別をしなくて済む
    • Guiceはパフォーマンスを最重要視しており、他のやつよりかなり遅くなる事はまず無いだろう。Java5の同期ライブラリを使いbuilderで処理するGuiceは超速い。DIではよりSpringより数百倍約100倍速い*2
  • アノテーションについて
  • AOPについて
    • Guiceは簡単に使えてメモリ消費も少ないメソッドインターセプトだけを用意している。更に重要な事は、これによってインターセプタ無しでメソッドを呼び出す可能性を下げている事だ*5
    • Guiceはメソッドごとに別のハンドラを用意しているので、パフォーマンスのオーバーヘッドは最小になっている

*1:これは http://code.google.com/p/google-guice/ に記載

*2:ベンチマークコード⇒http://google-guice.googlecode.com/svn/trunk/test/com/google/inject/PerformanceComparison.java

*3:これはサンプル見ないと何を言ってるのかよく分かりませんね。少なくとも私は…

*4:型で一致したりする例のやつ

*5:ここ自信なし…

Google Guice(その2) 最も単純にInjectするサンプル

一番単純なサンプルを、ユーザガイドから少し変えて書いてみます。あ、このドキュメントGoogle Docsだ。
構成は以下。

Service
Injectするインタフェース
ServiceImpl
Injectするインタフェースの実装クラス
Client
ServiceがInjectされるクラス
Main
起動クラス

まずServiceとServiceImpl。

public interface Service {
	String getResponse(String msg);
}
public class ServiceImpl implements Service {
	public String getResponse(String msg) {
		return "Re: " + msg;
	}
}

当たり前ですが、POJOです。そしてServiceを呼び出すClient。

import com.google.inject.Inject;

public class Client {
	@Inject
	private Service service;
	
	public void execute() {
		String response = service.getResponse("Hello");
		System.out.println(response);
	}
}

もう、どう見てもserviceをInjectする気満々ですね。「どこにInjectするか」は、アノテーション@Injectで指定するようです。
さて一番知りたいのは、何をするとこれがInjectされるのか。

public class Main {
	public static void main(String[] args) {
		Injector injector = Guice.createInjector(new MyModule());
		Client client = injector.getInstance(Client.class);
		client.execute();
	}
	
	static public class MyModule extends AbstractModule {
		@Override
		protected void configure() {
			bind(Service.class).to(ServiceImpl.class);
		}
	}
}

これだけでした。気になっていた部分は、

bind(Service.class).to(ServiceImpl.class);

で、今回の例では、bind(インタフェース).to(実装クラス) で「何をInjectするか」を設定しています。SpringだとXML定義を書くところですね。Injectorを作ってgetInstance()しているのは、SpringでApplicationContextを作ってgetBean()しているのと同じ感じですね。

という事で、実行するとめでたく

Re: Hello

と表示されました。

ところで

特にDIのパフォーマンスで困っている訳でも、XML定義が大きすぎて困っている訳でもない私がGuiceにちょっと興味を持っているのは、ソース見たらジェネリクスがすごい事になっていたからです。正直、最初見た時ソースの文法が一部理解できなくて「ジェネリクスをフル活用するとこんなソースになるのか!」と衝撃を受けました。
通常自分で組むプログラムでそこまで目一杯使うシチュエーションはあまり無さそうですが、気になる方はInjectorImplのソースをご覧あれ。