260 likes | 418 Views
今さら人には聞けない DI 入門. 2006.05.14 エスエムジー株式会社 小森 裕介( komori@smg.co.jp ). はじめまして!. 名前: 小森 裕介 Blog : http://d.hatena.ne.jp/y-komori/ 所属: エスエムジー株式会社( http://www.smg.co.jp ) 主な仕事: Java による集中監視制御システム設計・開発 集中監視制御フレームワークの設計・開発 Web アプリケーションシステムの設計・開発 教育・各種執筆活動 「 JAVA PRESS 」
E N D
今さら人には聞けないDI入門 2006.05.14 エスエムジー株式会社 小森 裕介(komori@smg.co.jp)
はじめまして! • 名前:小森 裕介 • Blog:http://d.hatena.ne.jp/y-komori/ • 所属:エスエムジー株式会社(http://www.smg.co.jp) • 主な仕事: • Javaによる集中監視制御システム設計・開発 • 集中監視制御フレームワークの設計・開発 • Webアプリケーションシステムの設計・開発 • 教育・各種執筆活動 • 「JAVA PRESS」 • 「日経ソフトウェア」「とことん作って覚える! Java入門」連載 • 「なぜ、あなたはJavaでオブジェクト指向開発ができないのか」 • Seasar2とのかかわり • S2Containerコミッタ(PropertyInterType)、S2JMSコミッタ
そんなあなたに 40分でDIコンテナの魅力 お伝えします! はじめに • どうも巷では「DIコンテナ」というのが 流行っているらしい・・・ • 興味はあるけど、ゆっくり勉強する時間ないし・・・ • どうせ今の仕事で使わないから、後回し・・・
DIで何が楽になるのか? • アプリケーションの変更が楽になる! • アプリケーションのテストが楽になる! • アプリケーションの再利用が楽になる! 生産性向上!
たった3クラスの 依存でも・・・ HitsuyouNaLogic Logger DataSource TottemoTaihen コンストラクタ渡し 依存クラスの 準備がとってもタイヘン! Factoryから取得 JNDIで取得 こんなコードにウンザリしていませんか? Before DI… public class TottemoTaihen { private DataSource ds; private Logger logger; private HitsuyouNaLogic logic; public TottemoTaihen(HitsuyouNaLogic logic) { this.logic = logic; // データソースの取得 Context ctx = new InitialContext(); DataSource ds = (DataSource)ctx.lookup("java:comp/env/jdbc/MySQL"); // ロガーの取得 this.logger = LoggerFactory.getLogger(this.getClass()); } public void doLogic() { ・・・本来の処理・・・ } } 本当に書きたいのは ここだけなのに・・・
DIならとってもカンタン! After DI !! public class DIdeKantan { private DataSource ds; private Logger logger; private HitsuyouNaLogic logic; public void doLogic() { ・・・本来の処理・・・ } public void setDataSource(DataSource dataSource){ this.dataSource = dataSource; } public void setLogger(Logger logger) { this.logger = logger; } public void setHitsuyouNaLogic(HitsuyouNaLogic logic) { this.logic = logic; } } 必要な処理のコーディングに 集中できる! 簡単なsetterメソッドを 用意するだけでOK!
HitsuyouNaLogic TottemoTaihen DataSource Logger HitsuyouNaLogic Logger DataSource DIdeKantan Before DI ・ After DI Before DI… 必要なオブジェクトは 自分で準備するのが常識! Create! Create! Create! だから、とってもタイヘン! After DI !! 必要なオブジェクトは DI Container が 用意(Injection)してくれる! DI Container Injection! Injection! Injection! クラス本来の記述に専念できる!
寿司にたとえるDI-非DIなちらし寿司 非DIなちらし寿司 • 材料が多くて準備がタイヘン! • 材料が揃えば混ぜるだけなのに・・・ ソースコードにたとえれば・・・ public classちらし寿司 { private酢飯 sumeshi; privateまぐろ maguro; private錦糸卵 kinshiTamago; privateいくら ikura; privateえび ebi; privateうに uni; privateにんじん ninjin; privateしいたけ shiitake; publicちらし寿司() { 酢飯準備(); まぐろ準備(); ・・・省略・・・ しいたけ準備(); } public voidまぜる() { 酢飯の上に材料をちらす } private void酢飯準備() { ・・・酢飯の準備・・・ } private voidまぐろ準備() { ・・・まぐろの準備・・・ } ・・・省略・・・ private voidしいたけ準備() { ・・・しいたけの準備・・・ } } えび まぐろ うに 錦糸卵 にんじん いくら しいたけ
寿司にたとえるDI-DIな手巻き寿司 DIな手巻き寿司 • 寿司ネタは最初から用意されている • あとは好きなものを巻くだけ! ソースコードにたとえれば・・・ 酢飯 まぐろ 厚焼き卵 public class手巻き寿司 { private酢飯 sumeshi; privateまぐろ maguro; private厚焼き卵 atsuyakiTamago; privateきゅうり kyuuri; privateえび ebi; privateいくら ikura; public void巻く() { お好きにどうぞ! } きゅうり えび いくら 「手巻き寿司」のつもり ↑ ※ setter の記述は省略しています
現在利用できる代表的なDIコンテナ • Spring Framework • http://www.springframework.org/ • 世界的に有名 • Seasar2 • http://www.seasar.org/ • 世界的には、(今のところ)マイナー • 純国産のプロダクト • Spring には無い利点がいっぱい
DI Container 取得 DIdeKantan DIdeKantan DataSource DataSource Logger Logger HitsuyouNaLogic 登録 HitsuyouNaLogic DIコンテナは何をしてくれるのか? • 必要なクラスをDIコンテナに登録しておくと、コンテナから 取り出すときに依存オブジェクトをセット(Injection)してくれる 設定(XML)ファイル <components> <component class=“DIdeKantan” /> <component class=“DataSource” /> <component class=“Logger” /> <component class=“HitsuyouNaLogic” /> </components> ① 対象オブジェクトの生成 ② 依存オブジェクトの生成 ③ 依存オブジェクトのセット がおこなわれる オブジェクトの生成はコンテナまかせ!
DI Container <components> <component class=“DIdeKantan”> <aspect class=“TraceInterceptor” /> </component> <component class=“HitsuyouNaLogic”> <aspect class=“TraceInterceptor” /> </component> </components> DIdeKantan HitsuyouNaLogic 取得 DIdeKantan HitsuyouNaLogic ログ出力機能 ログ出力機能 登録 http://s2container.seasar.org/ja/aop.html More Info! DIのコンテナのもう一つの利点-AOP • DIコンテナはオブジェクトを生成するだけでなく、 オブジェクトに動的な機能追加もできる 横断的に実現したい機能を 「アスペクト」として登録しておく 設定(XML)ファイル コンテナから取得した時点で 機能が組み込まれている • ソースコードの修正は一切不要! • 自動生成などの面倒な作業もなし!
DIdeKantan <<interface>> HitsuyouNaLogic <<interface>> HitsuyouNaLogic HitsuyouNaLogicImpl MockHitsuyouNaLogic HitsuyouNaLogicImpl 「設計と実装の分離」の実現 • DIの世界では「設計と実装の分離」が本当に実現できる DI Container <components> ・・・ <component class=“HitsuyouNaLogicImpl” /> ・・・ </components> private HitsuyouNaLogic logic; ・・・ logic.foo(); ・・・ インターフェースに 依存 実装クラスを登録 テスト用のモックオブジェクトを作った場合・・・ DI Container <components> ・・・ <component class=“MockHitsuyouNaLogic” /> ・・・ </components> モックオブジェクトに変更 依存元(DIdeKantan)のソースコードは修正不要!
DI×AOPの威力 • DIとAOPの組み合わせでできること • モックオブジェクトの提供 • 各種プーリングの実現 • トランザクションの実現 • 分散オブジェクトの実現 ・・・etc 横断的な機能追加 設計と実装の分離 どんな実装クラスを用意するかは コンテナの設定次第! DI Container 元の実装クラス テスト用モッククラス 利用側 各種アスペクト 適用 元の実装クラス 利用する側からは インターフェースしか見えていない リモートオブジェクトを呼び出すスタブ
デモ:DIでジャンケン! • ジャンケンプログラムでDIの効果を体験しよう!
RandomTactics StoneOnlyTactics CyclicTactics ComputerPlayer Strategyパターンで手の出し方を変える ランダム Player Tactics グーだけ ジャンケンの手を決める処理を Tacticsへ委譲 グー・チョキ・パー 順番に 実装クラスの変更を DIコンテナで行う
Tacticsのインジェクション ComputerPlayerクラス publicclass ComputerPlayer extends PlayerImpl { private Tactics tactics; public int showHand() { return tactics.readTactics(); } publicvoid setTactics(Tactics tactics) { this.tactics = tactics; } } S2Containerが自動的に setterを呼び出してTacticsの 実装クラスをセットしてくれる Tacticsの実装クラスを 意識する必要なし! Tacticsインターフェース public interface Tactics { publicint readTactics(); }
http://s2container.seasar.org/ja/DIContainer.html#AutoBindingModehttp://s2container.seasar.org/ja/DIContainer.html#AutoBindingMode More Info! http://s2container.seasar.org/ja/DIContainer.html#ComponentAutoRegister More Info! http://kijimuna.seasar.org/ More Info! http://s2container.seasar.org/ja/aop.html#AOPInterType More Info! http://s2container.seasar.org/ja/benchmark/20060412_seasar_vs_spring.pdf More Info! DIコンテナに対する5つのギモン • 依存関係はどうやって判断するの? • Seasar2なら、インターフェースに基づいて自動判断します • 結局設定ファイルをたくさん書くのでは? • Seasar2なら、AutoRegisterでカンタンに登録! • 設定ファイルのデバッグが大変? • Kijimuna(キジムナ)で記述の誤りがチェックできます! • 結局はリフレクションでしょ、遅くないの? • 独自のキャッシュ機構で速度低下はほとんどありません • Seasar2はSpringと比較して2~300倍高速です • Setterを書くのが面倒くさい! • PropertyInterType で setter いらず!
PropertyInterType でsetter不要! アノテーションの記述 のみでsetterを 動的に生成! public class DIdeKantan { private DataSource ds; private Logger logger; private HitsuyouNaLogic logic; public void doLogic() { ・・・本来の処理・・・ } public void setDataSource(DataSource dataSource){ this.dataSource = dataSource; } public void setLogger(Logger logger) { this.logger = logger; } public void setHitsuyouNaLogic(HitsuyouNaLogic logic) { this.logic = logic; } } public class DIdeKantan { @Propery DataSource ds; @Property private Logger logger; @Property private HitsuyouNaLogic logic; public void doLogic() { ・・・本来の処理・・・ } } setterすら書きたくない! ※ PropertyInterType は S2Container 2.4.0 beta1 ~ 利用できます ※ S2Container 2.4 系では、EJB3.0 対応のため、さらに便利なフィールドインジェクションが利用可能になる予定です
No! DIコンテナの誤った使い方 • なんでもDIコンテナに放り込めばよい? • DIコンテナに登録するのは、 再利用可能な「コンポーネント」の単位 • どんな単位で登録するかは、きちんとした設計が必要 • Webアプリケーションならば、 DIベースの設計手法「Goya」を参考にするとよい ※ Goal Oriented Yielding Approach 『WEB+DB PRESS vol.31』 (技術評論社) 「Goyaで学ぶDIベースのシステム設計」 More Info!
DIコンテナの使いどころ • DIコンテナのメリットはなんとなくわかった・・・ でも、 開発現場で どう役立てればいいの? DIコンテナの機能を フルに使い切って設計するのは、 結構ムズカシイ! そこで・・・ まずは、S2Containerを100%生かして作られた 周辺プロダクトを使ってください!
S2Container S2AOP S2Unit S2Tx S2DBCP S2JDBC http://www.seasar.org/products.html More Info! S2ファミリーを使ってみよう! 代表的なS2ファミリー(Java) アプリケーション Tuigwaa 開発用ツール O/Rマッピング Kijimuna S2Javelin S2Hibernate ビジネスロジック S2JSF Plugin S2Dao S2Buri プレゼンテーション 分散技術 S2Struts S2Flex S2Axis S2RMI S2JMS S2Remoting S2JCA S2JSF (Teeda) Mayaa ・・・他製品との連携を実現するもの ・・・開発中プロジェクト ・・・本カンファレンスで取り上げられているもの A
EJB3への潮流 • 「アンチEJB」として始まったDIコンテナの流れ • DIコンテナの考え方は、EJB3の仕様に 取り込まれた • Seasar2の弱点は「非標準」であること Seasar2 2.4ではEJB3に対応予定!
Seasar2をさらに知りたい方へ • 『Seasar入門 ~はじめてのDI&AOP~』 • 税込価格:3,570円 • 出版社:ソフトバンククリエイティブ • ISBN:4797331968 • 監修:ひが やすを • 著:須賀 幸次/木村 聡/西川 麗/高安 厚思/白井 博章/椎野 峻輔/岡 薫/藤村 浩士 DIコンテナの基礎から 各種S2ファミリーの使い方まで 幅広く網羅 • Seasarの使い方に困ったら・・・ • Seasar-user メーリングリスト • https://www.seasar.org/mailman/listinfo/seasar-user
ご質問について スピーカーブースで お待ちしています 気軽にお越しください
ご静聴 ありがとうございました