1.Dependency Injectionとは
概要
DI(Dependency Injection)は、「依存性の注入」などと訳されたり、説明されたりします。
この説明って何か小難しいですよね?英訳をそのまますると、ままこんなことがあります。
ここでは、もっと自由に考えて説明していこうと思います。
もっと具体的な使い方等を見てみたい方はTipsなどをみてもらうといいかもしれません。
DIとは?
DIとは結局は、外部定義の拡張だと思うのです。
Windowsでいうところのiniファイルの豪華版みたいなものです。Javaでいうところのプロパティファイルです。
【参考:外部定義ファイルの例】
mode=1
timeout=100
connect=10.10.0.10
外部定義しておけば、タイムアウト値や接続先などを後でプログラムを変えることなく動作を変えられますね。
ただし、これだとタイムアウト値の100のような定数のみしか変更できません。
ここでちょっと考えます。
もし使用するクラスも設定で変更できるとさらに便利そうです。例えば、新しい機能を持ったクラスを追加したときに入れ替えるなんてことを考えます。
【クラス設定のイメージ】
#file=com.my.CsvReader
file=com.my.XmlReader
上記イメージは、「CSVで記述したファイルからデータを読み込んでいましたが、お客様の都合でXML形式に変更した」というイメージをしてみました。
これだけでも設定で変更できる幅が広がります。
さらに、コンストラクタの引数に与える値や、setterなどで与える値も設定できるともっと設定変更の幅が広がります。
それがSpringのDIで用意されている設定方法です。
Springで用意されている設定方法
では、少し具体的にSpringで用意されている設定ファイルの記述方法をみてみましょう。
【SpringのDIでの設定ファイルのイメージ】
<bean id="executor" class="com.my.Executor" > ───①
<property name="dataReader" ref="dataReader"/>
<property name="file" value="file:c:/temp/data.dat"/>
</bean>
<bean id="dataReader" class="com.my.XmlReader" /> ───②
Spring設定ファイルでは、ファイルパスのような定数値(例: c:/temp/data.dat)も、使用するクラス(例: com.my.Executor)も記述できます。
記述はXMLで行います。
最初のbeanタグ①を見てください。
propertyタグのref 属性では、データの読み込み方法を知っているクラス(beanタグで設定された②)を設定しています。
クラスだけではありません。もうひとつのpropertyタグでは、ファイルパスも設定しています。
このようにして、Springでは定数値と同時に、クラス間の関係も設定していきます。
クラス間の関係は別の言い方をすると「依存関係」です。
このように依存関係を設定ファイルで外部から規定しているため、「依存性の注入」などと英語では呼んでいるようです。
補足:
propertyタグはsetterを表しています。
例えば、タグ①のname="file"は、setFile(Resource file) というメソッドに、ファイルパスを渡すことを意味しています。
Springは、上記設定を読み込むと、内部で以下のような処理を実行します。
※イメージなので、なんとなくご理解いただければ大丈夫です。
DataReader dataReader = new XmlReader();
Executor executor = new Executor();
executor.setDataReader(dataReader);
executor.setFile(new FilePathResource("c:/temp/data.dat"));
そして、上記を実行した結果できるexecutorを取り出すことができます。
取り出し方は、以下のようにします。
【SpringのDIを使用したコードのイメージ】
Executor executor = (Executor)applicationContext.getBean("executor");
executor.run();
applicationContextはSpringの設定ファイルを読み込み、読み込んだ内容を利用するためのオブジェクトと思ってもらえば大丈夫です。
設定ファイル上、beanタグで記述した内容をid名で指定して取得できます。
SpringのDIを使用する理由
もちろん上記の機能拡張や変更は、Spring設定ファイルではなくソースコードを直接変えることでも対応できます。
【ソースコードの変更によるクラス入れ替えのイメージ】
//DataReader reader = new XmlReader();
DataReader reader = new JsonReader();
:
しかし、ソースコードを変更する方法にはいくつか弱点があります。
・newした箇所をすべて変更しないといけない。
・コンストラクタに引数があったり、setterで値を設定する必要がある場合、修正漏れの可能性が大きくなる。
・1つのオブジェクトのインスタンスを様々なクラスで使用したい場合、各クラスにインスタンスを渡す機構を自分で作らないといけない。
・どんなに再利用性の高いクラス(部品)を作っても、ソースに手を入れなければならない。
・依存関係を持っているため修正のたびにソースコードを触わる必要があり、部品を扱っているという感覚が心理的に芽生えない。
・JUnitなどのテストのためだけに、ソースを変更しなければならない。
Springで外部から依存関係を設定できれば、単体テストのための設定ファイルを本番用と別に作るだけですむ。
・様々なライブラリを使用して多機能な基盤を自作すると多数のクラスをimportするため、使用しないライブラリもすべて起動時にロードしなければならなくなる。
Springを使用すればDIできるので、DIしたクラスが必要とするライブラリのみimportされることになる。
このあたりは、開発の経験が長い方なら気づく問題点です。
これらの問題に対してSpringは助け舟を出してくれます。
また、Springを使用すれば外部定義ファイルの読み込みや、クラスへの値の設定などを実装する必要がなくなります。
Spring Tipsもご覧ください。
Created Date: 2010/11/27