Spring FrameworkはIoCコンテナとかDIコンテナとか言われています。
要は、今までコードの中に書いてたクラス間の依存関係をSpring側で面倒見てあげるというものです。
代償としてXMLファイルを書かなければなりません。(新機能とか色々使えばそうでもないけど)
ということで、今回は依存性の注入をしてみようと思います。
依存性の注入方法には、代表的なもので2つあります。他にもありますが、とりあえず基本的なパターンでよく使うと思われる2つに絞ります。
- セッターインジェクション
- コンストラクタインジェクション
名前からわかるように、各々セッターを使ってクラスのインスタンスを設定するか、コンストラクタで設定するかの違いです。
Spring的には、セッターインジェクションがオススメみたいなことが書いてありました。
(英語力が皆無なので誤読してる可能性あり)
なんでも、「理想を語るならコンストラクタインジェクションだけど、セッターインジェクションの方が色々便利だよ」と言う事らしいです。
詳しくは、Springのリファレンスを見てください。
ということで、今回はspring2bean.beans.MyServiceクラスとspring2bean.beans.MyLogicクラスを使って依存性注入をしてみようと思います。
MyServiceクラスがMyLogicクラスを使うといった形になっています。
MyServiceクラス
package spring2bean.beans;
// 左辺値と右辺値を受け取ってMyLogicのaddメソッドに渡すだけのクラス
public class MyService {
private MyLogic logic;
private int lhs;
private int rhs;
public MyService() {
}
// コンストラクタで初期化
public MyService(MyLogic logic, int lhs, int rhs) {
this.logic = logic;
this.lhs = lhs;
this.rhs = rhs;
}
public int execute() {
return logic.add(lhs, rhs);
}
// セッターでも初期化可能
public void setLogic(MyLogic logic) {
this.logic = logic;
}
public void setLhs(int lhs) {
this.lhs = lhs;
}
public void setRhs(int rhs) {
this.rhs = rhs;
}
}
MyLogicクラス
package spring2bean.beans;
public class MyLogic {
public int add(int x, int y) {
return x + y;
}
}
MyServiceクラスには、コンストラクタからでもセッターからでもフィールドの値の設定が可能なつくりにしました。
このクラスを使って、コンストラクタインジェクションとセッターインジェクションの場合の定義例を以下に示します。
application.xml
<?xml version="1.0" encoding="UTF-8"?>
<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-2.5.xsd">
<!-- サービスから使われるロジック -->
<bean id="myLogic" class="spring2bean.beans.MyLogic" />
<!-- セッターインジェクション -->
<bean id="setterService" class="spring2bean.beans.MyService">
<!--
propertyタグを使って、どのプロパティに何をセットするかを記述する。
refを使って既に定義されているbeanを参照することも、valueを使って
intやString等を直接設定することが出来る。
-->
<property name="logic" ref="myLogic" />
<property name="lhs" value="100" />
<property name="rhs" value="200" />
</bean>
<!-- コンストラクタインジェクション -->
<bean id="constructorService" class="spring2bean.beans.MyService">
<!--
constructor-argタグを使って、何番目のコンストラクタの引数に何を設定するかを
指定する。
propertyタグと同じようにrefとvalueが使える。
こっちはpropertyタグにはないtype属性があって、そこに型を指定できる。
-->
<constructor-arg ref="myLogic" />
<constructor-arg type="int" value="1000" />
<constructor-arg type="int" value="150" />
</bean>
</beans>
簡単な説明をXML中にコメントとして追加しました。これを読み込んでサービスの処理を実行するMainを書いて動きを見てみます。うまくいけば、setterServiceのexecuteは300を返して、constructorServiceのexecuteは1150を返すはずです。
Main.java
package spring2bean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import spring2bean.beans.MyService;
public class Main {
public static void main(String[] args) {
// ApplicationContext作って~
ApplicationContext ctx = new ClassPathXmlApplicationContext("application.xml");
// サービスのインスタンスを取得して~
MyService setterService = (MyService) ctx.getBean("setterService");
MyService constructorService = (MyService) ctx.getBean("constructorService");
// 処理実行!
System.out.println("setterService#execute = " + setterService.execute());
System.out.println("constructorService#execute = " + constructorService.execute());
}
}
実行結果は…
setterService#execute = 300
constructorService#execute = 1150
思ったとおり!
今回のを簡単にまとめると・・・
依存性の注入にはセッターインジェクションとコンストラクタインジェクションの2通りがある。
セッターインジェクションにはpropertyタグを使う。
コンストラクタインジェクションにはconstructor-argタグを使う。
ref属性で、既に定義されているbeanを参照できて、value属性で直接値を設定できる。
ということで今回はここまで。