かつのりの日記2

わんくまでは珍しいJavaを中心とした日記です

目次

Blog 利用状況

書庫

日記カテゴリ

いろいろリンク

DIコンテナまとめ

誰か彼かがDIコンテナについて過去に書いているかもしれませんが、再度まとめです。

DIコンテナのDIとはDependency Injectionです。直訳すると依存性の注入になります。そしてコンテナとはオブジェクトを複数管理する仕組みです。DIコンテナは、管理しているオブジェクト間の依存性を、ある程度自動的に解決する仕組みをもったコンテナとなります。

DIコンテナには2つの大きな目的と、1つの大きな拡張機能があります。それでは1つずつ見てみましょう。

依存性の解決

DIコンテナは再帰的に管理しているクラスの依存性を解決します。依存性とは大きく分けて2種類あります。それはコンストラクタの引数とプロパティです。例えば以下のようなクラス郡が存在するとします。

public class Car{

	private Engine engine;

	private Tire tire;

	public Car(Engine engine, Tire tire){
		this.engine = engine;
		this.tire = tire;
	}
}

public class Engine{
}

public class Tire{

	private Wheel wheel;

	public Tire(Wheel wheel){
		this.wheel = wheel;
	}
}

public class Wheel{
}

正しいCarのインスタンスが欲しい場合、以下のようなコードによる手続きが必要になります。

public class CarClient{

	public static void main(String[] args){
		Wheel wheel = new Wheel();
		Tire tire = new Tire(wheel);
		Engine engine = new Engine();
		Car car = new Car(engine, wheel);
	}
}

普通のコードで書けば手続きが複雑になり、手続きを間違えればバグの原因となります。もし適当なDIコンテナがあるとして、利用した場合以下のようなコードになります。

public class CarClient2{

	public static void main(String[] args){
		Container container = ContainerFactory.getContainer();
		Car car = container.getInstance(Car.class);
	}
}

サンプルのパターンで解説すると、クライアントはDIコンテナにCarのインスタンスを要求します。DIコンテナはCarのコンストラクタが依存しているEngineのインスタンスとTireのインスタンスをDIコンテナ自身に要求します。Engineは他の型に依存していませんが、TireはさらにWheelに依存します。ここでWheelのインスタンスを再度DIコンテナ自身に要求します。

この様にDIコンテナは自身の設定を元に、プロパティやコンストラクタが依存する型を再帰的に解決します。

疎結合のサポート

DIコンテナは疎結合をサポートする目的でも利用されます。疎結合とはクラス間の結合度が薄い状態です。Javaにおける結合度は、コンクリートクラスに対する依存度で計られます。

上記コードではCarはEngineというコンクリートクラスとTireというコンクリートクラスに依存します。CarとEngineとTireは同じ人が作れば問題はありません。しかしそれぞれベンダーが違う場合、綿密に打ち合わせしなければなりませんし、EngineとTireが存在しなければ、そもそもCarを実装する事はできません。そこで依存度を疎結合にするためにインターフェイスが登場します。

ではサンプルコードを見てみましょう。

まずはインターフェイス郡です。

public interface Tire{
}

public interface Engine{
}

そして実装です。

public class StudlessTire implements Tire{

	private Wheel wheel;

	public StudlessTire(Wheel wheel){
		this.wheel = wheel;
	}
}

public class SpikeTire implements Tire{

	private Wheel wheel;

	public SpikeTire (Wheel wheel){
		this.wheel = wheel;
	}
}

public class DieselEngine implements Engine{
}

public class GasolineEngine implements Engine{
}

 

上記のようなコードが存在するとき、DIコンテナはCarに必要なEngineとTireのインスタンスを一意に特定する事はできません。そのために設定が必要となります。Tireが要求されたときにStudlessTireのインスタンスを返すのか、SpikeTireのインスタンスを返すのか、それを設定します。Engineも同様です。

DIコンテナを利用すると以下のようなコードになります。

public class CarClient3{

	public static void main(String[] args){
		Container container = ContainerFactory.getContainer();
		Car car = container.getInstance(Car.class);
	}
}

このコードはCarClient2と全く同一です。インスタンスの依存性解決が行われる点は同じであるからです。例えばTireはStudlessTire、EngineはDieselEngineを設定によって選択した場合、そのインスタンスを包含するCarが生成されます。

ここまでは先の章と大差ないと感じるかもしれません。ここからが疎結合サポートの本領発揮です。

例えばStudlessTireからSpikeTireに取り替えたいときはどうすればよいでしょうか。答えは簡単です。単純に設定を変更すればよいのです。仮にテスト済みのコードがあっても、そのコードを修正する必要はないのです。

さらにEngineが何も完成していない状態であるとしましょう。そこでモックのEngineを作ってDIコンテナに設定して置けばよいのです。EngineがなくてもCarを取り合えず実装する事はできるのです。そして実装したCarのコードをテストすればCarは完成です。Engineが完成したらそのEngineをDIコンテナに設定し、正しいCarがクライアントに引き渡されるのです。

AOPのサポート

AOPとはAspect Oriented Programming(アスペクト指向プログラミング)の略です。書くと長くなるので、リンクだけ置いておきます。

http://ja.wikipedia.org/wiki/%E3%82%A2%E3%82%B9%E3%83%9A%E3%82%AF%E3%83%88%E6%8C%87%E5%90%91%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0

DIコンテナとAOPは全く関係ないのですが、DIコンテナは暗黙的に型を解決する機構を持つ為、AOPと相性がよいのです。

上記コードを元に説明しますが、CarはEngineのインスタンスに依存していますが、DIコンテナによってGasolineEngineのインスタンスが返される設定になっているとします。そこでクライアントがEngineにターボ機能を追加するケースを考えてみましょう。

クライアントがEngineにターボ機能を追加しようとする場合、DIコンテナなしではEngineの実装を改造するか、AOPライブラリを使用してターボをサポートするようにコードを書き換えます。これはテスト済みのコードを改造するというリスクが生じます。

しかしDIコンテナとコラボレーションすることによって、DIコンテナは自動的にGasolineEngineのクラスを拡張してターボ機能を追加します。クライアントはAOPの設定を行うだけでコードの修正を行う必要はないのです。

適用例

CarとかEngineとか・・・抽象的過ぎてイメージしにくいかもしません。そこで実際のアプリに置き換えてみましょう。

まずは、データアクセスオブジェクトとビジネスロジックです。

public interface EmployeeLogic{

	Employee[] getEmployees();
}

public interface EmployeeDAO{

	Employee[] select(String sql);
}

public class EmployeeDAOImpl implements EmployeeDAO{

	public Employee[] select(String sql){
		//SQL Execute...
	}
}

public class EmployeeLogicImpl implements EmployeeLogic{

	private EmployeeDAO employeeDAO;

	public EmployeeLogicImpl(EmployeeDAO employeeDAO){
		this.employeeDAO = employeeDAO;
	}

	public Employee[] getEmployees(){
		return employeeDAO.select("select * from Employee");
	}
}

そしてクライアントコード。

public class Client{

	private EnployeeLogic logic;

	public Client(EmployeeLogic logic){
		this.logic = logic;
	}

	public void process(){
		Employee[] employees = logic.getEmployees();
		for(Employee employee : employees){
			System.out.println(employee);
		}
	}
}

 

クライアントコードはビジネスロジックだけに関心を持てばよく、ビジネスロジックが完成していなければモックで代用します。ある程度完成した直後にSQLをログ出力したいとなった場合、EmployeeDAOに対してAOPでログ用のインタセプタを設定します。クライアントのコードはその間一切修正する必要はありません。

DIコンテナの実装

DIコンテナの中身はどうなっているのでしょうか。それは各DIコンテナで全然違いますが、(当たり前ですが)考え方は概ね似ています。

  1. 設定フェーズでクラスを集める
  2. 要求があったときにインスタンスを生成する
  3. クラスがロードされていなければクラスをロードする
  4. AOPの利用が必要な場合、クラスを拡張してロードする
  5. インスタンス生成時に必要な依存クラスのインスタンスを生成する(再帰的に2へ)
  6. その依存インスタンスを利用してインスタンスを生成する
  7. プロパティの型を走査して、プロパティの型に該当するインスタンスを生成する(再帰的に2へ)
  8. プロパティに生成したインスタンスを設定する
  9. クライアントへインスタンスを返す

という流れになります。インスタンスにはライフサイクルの概念があって、インスタンスが再利用される場合は生成及び設定のフェーズがスキップされます。よくあるライフサイクルは、

  • シングルトン(一意)
  • プロトタイプ(都度生成)
  • リクエスト(APサーバのリクエスト)
  • セッション(APサーバのセッション)

などです。(DIコンテナによってはスコープと呼ばれたりもします。)

さっきから「設定」という言葉が度々登場していますが、よくあるパターンとしてはXML形式の設定ファイルが利用されますが、Googleで開発されたGuiceというDIコンテナみたいに設定ファイルを利用しないものもあります。

最後に長くなりましたが、DIコンテナは.NETにもありますが、Javaでは比較的メジャーな存在になっています。いまではDIコンテナなしの開発は考えられないくらいに浸透しつつあります。新規で開発する機会がありましたら、一度触れてみてはいかがでしょうか。

投稿日時 : 2007年8月29日 0:09

Feedback

# re: DIコンテナまとめ 2007/08/29 13:09 凪瀬

DIでの設計を考える場合、まずライフサイクルを想定すると思うのですが、
性質上、比較的長いライフサイクルを持つオブジェクトにだけ適用しているのではないでしょうか。
後で自分の考えるDIの拡張についてエントリ書きますね。

# re: DIコンテナまとめ 2007/08/29 13:35 かつのり

オーバーヘッドがそれなりにあるので、
基本的にはシングルトンで扱うことが多いですが、
他にセッションやリクエストが使われます。
なかなかプロトタイプが必要なケースは少ないですね。
この辺はドメインオブジェクトを適用するときに使うことが多いと思います。

適用例ではClientのコードを生成する部分を書いていませんが、
例えばMVCフレームワークではコントローラで生成します。
StrutsならActionですね。

アプリを実装する側では、DIコンテナによって、
ゴニョゴニョされるというのは意識しますが、
基本的にDIコンテナ本体を意識しません。
コンテナがチラチラと実装コードに出てくると、
コンテナに依存する実装が出来上がってしまうためです。

この辺はIoC[制御の反転(Inversion of Control)]といわれるところです。
あくまで制御するのではなく制御されるコードを書くということですね。
DIコンテナはそのためのフレームワークになります。

この辺はコメント欄だけではなく第2弾を書こうかな。

# re: DIコンテナまとめ 2007/08/29 15:24 凪瀬

「制御の反転」は何の制御が反転してるんでしょう?

自分は実装よりでDIを解釈してるから、本来のDIの概念といくらかずれた理解をしているんだろうとは思っています。
そこからネタが出てくるならそれはそれで面白いからいいやとも思っていますがw

# re: DIコンテナまとめ 2007/08/29 15:42 かつのり

インスタンスの依存関係がツリー状になっている場合、
通常の手続きでは末端のノードから、自分で作成して構築していきます。
CarClientのような手続きです。これは自前でオブジェクトを制御しているという状態です。

これが反転すると、制御されるコードを意識して作成することになります。
ルールに沿った形でコンストラクタとプロパティを書くことにより、
コンテナ任せになりますが、インジェクションという制御が行われるわけです。

制御の手続きを意識するか、制御されることを意識するか、
これが制御の反転という考え方です。

ただし制御の反転だけではどんなフレームワークでも当てはまります。
StrutsのActionもコントローラから制御されているわけで・・・
そこで依存性注入という言葉が生まれたみたいですね。

# DIコンテナの拡張について考える 2007/08/29 19:09 凪瀬 Blog

DIコンテナの拡張について考える

# the Kelly bag and the Hermes Evelyn GM Bag. Order your Hermes bag today! 2013/04/02 4:52 Aqualalef

ekDb gkS ghIm VoqFj TksRb http://www.2013chaneljp.com/ ifXv bcO skYm GzwPa http://www.2013chaneljp.com/ xsMo atJ taOe JprEl GwjYk http://www.2013chanelnew.com/ csHc bcQ kcCx YecLa http://www.2013chanelnew.com/ thYf zvO ykMh WkrGy ZjxKy http://www.chanelbuyja.com/ tkBo csV boNg VaaEw http://www.chanelbuyja.com/ miHs miG taAu XdvWs ZauPg http://www.chanelcojp.com/ kyRg gpL thNq SywAe http://www.chanelcojp.com/ fqBo gyC gyPm WbsGm XtrOs http://www.chanelhotjp.com/ reLq llN yeLx OfbJt http://www.chanelhotjp.com/ fbUq hdX miEx CveTw ZtqKs http://www.chanelsaleja.com/ klCd rbC hsLa GhjTh http://www.chanelsaleja.com/ nbMi pwY tqDk TcqNo PjnXc http://www.chaneltopjp.com/ ioJm vlM omSl HulXn http://www.chaneltopjp.com/ wlFy xuF gnJz XtnBr PpwEk http://www.chanelyahoo.com/ cgQe leB xdLl PnbJf http://www.chanelyahoo.com/ efIx vlC irJc YajZd UqoHi http://www.newchanel2013.com/ njTn tqZ gbNe PqrGl http://www.newchanel2013.com/ zwNw coP onOu EqmHj BobVx http://www.newchaneljp.com/ yfOf lxV bsRb GuzFr http://www.newchaneljp.com/ bcZb ugP apMz AwdOi VooMq http://www.okchaneljp.com/ lhXb zfM izCa DcbTc http://www.okchaneljp.com/

# Prada opening upon supplies a rank of Prada on the block in behalf of everyone. 2013/04/03 5:23 Brisedued

urZd sxS qfYm WpnOu FmjHn http://www.2013chaneljp.com/ vdAw stE mhKn TuvXv http://www.2013chaneljp.com/ zvPb rxD llRm UguNv XmiNm http://www.2013chanelnew.com/ tfUi xgJ mbYi XzeJz http://www.2013chanelnew.com/ rqTx jgA isIj PnvEj MidDi http://www.chanelbuyja.com/ vlKo zxJ xxMz SzyHd http://www.chanelbuyja.com/ zdKh ipS tqKk WtjSp NdsLv http://www.chanelcojp.com/ jrMz ocN kaVy UstYz http://www.chanelcojp.com/ ciSp otP eaYd VzjZg MhjNr http://www.chanelhotjp.com/ tlRl odD rjJw MzvKu http://www.chanelhotjp.com/ rbWe sxP uwQb FggHr PkaLn http://www.chanelsaleja.com/ qqHv ipM poNc QipNq http://www.chanelsaleja.com/ dwSj dbO wuVf JcfQq TgbIy http://www.chaneltopjp.com/ rvLf cjF fpHj RyhQi http://www.chaneltopjp.com/ doXp muZ wnIp FfzUk SlfEd http://www.chanelyahoo.com/ gdCs hiU kgEi CkmDi http://www.chanelyahoo.com/ umWt jdG yfSe JfaQh GhhFx http://www.newchanel2013.com/ wcDu blW hcZf HavGf http://www.newchanel2013.com/ uoFj gxG fhXc SqpXd HvgKz http://www.newchaneljp.com/ ehNt puI zhUw BgaGf http://www.newchaneljp.com/ mzMw bvT iqDo SncVj FhoRh http://www.okchaneljp.com/ ltTk syE xqDz XggCi http://www.okchaneljp.com/

# Celine handbags is a classical security brand.As a distributors of celine handbag, 2013/04/05 5:42 Faiseeequip

zvYo zxB cpAw EcwNt NwhPq http://www.2013chaneljp.com/ ayIt gbN oyCo RchKz http://www.2013chaneljp.com/ rkWj saQ vtZv PedZa PinIy http://www.2013chanelnew.com/ ifHz noP adJp DdjMk http://www.2013chanelnew.com/ yxUa mrW ofSk VofPn RtkYm http://www.chanelbuyja.com/ gnFm pzD spMa QbnBk http://www.chanelbuyja.com/ uqUl cnD uzQx RzqPv KyaOa http://www.chanelcojp.com/ wcKb ivV imJl VbiTc http://www.chanelcojp.com/ mjBu peQ ztPq WdpRd KymSd http://www.chanelhotjp.com/ ktBg mtH apJi CcfBc http://www.chanelhotjp.com/ xjBp woH czJh LfaZh RlzIa http://www.chanelsaleja.com/ voFt ogP jdRw XksXh http://www.chanelsaleja.com/ nkRb fjD bzRm WlyJs OcbVt http://www.chaneltopjp.com/ wsWl zaJ zpNv XwiLz http://www.chaneltopjp.com/ dhEi erO axWi HgsPo ZtvUt http://www.chanelyahoo.com/ vrUp iqL fmSo XevUe http://www.chanelyahoo.com/ aqAd lsR jeVs CmbPf XtjVe http://www.newchanel2013.com/ ufBf eaV pxBz AjyCt http://www.newchanel2013.com/ vuRd ybK fzGd BrtQw NvvIy http://www.newchaneljp.com/ npWv reL gzMj SdkCh http://www.newchaneljp.com/ otTo zoM yrLj FezMb JvuPc http://www.okchaneljp.com/ ygGx bzL ouIa LtlIy http://www.okchaneljp.com/

タイトル  
名前  
Url
コメント