Spring3 DIでHello World

開発環境も整ったところで、定番のHello WorldをSpring3のDIを使ってやってみました。


[File]-[New]-[Spring Template Project]を選択して「New Template Project」ウィザードを起動します。

①「Simple Spring Utility Project」を選択して[Next]ボタン押下
②[Project name]に「HelloWorld」、top-level packageに「jp.org.tomotaro」を入力して[Finish]ボタン押下


すると、次のようなファイル群が生成されます。

app-context.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"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">

	<description>Example configuration to get you started.</description>

	<context:component-scan base-package="jp.org.tomotaro" />

</beans>

context:component-scanタグでBeanをjp.org.tomotaroパッケージから検索することを指定しています。

Service.javaは下記のような内容のインタフェースです。

package jp.org.tomotaro;

public interface Service {
	String getMessage();
}

getMessageメソッドのみを定義しています。

ExampleService.javaがServiceインタフェースの実装クラスです。

package jp.org.tomotaro;

import org.springframework.stereotype.Component;

@Component
public class ExampleService implements Service {
	public String getMessage() {
		return "Hello world!";	
	}
}


getMessageメソッドで「Hello world!」という文字列を返しているだけです。
注目すべきは@Componentアノテーションです。このアノテーションを付けることによって、component-scanの検索対象のBeanとなります。

ExampleConfigurationTests.javaとExampleServiceTests.javaはExampleSerivseクラスのJUnitテストケースです。
それぞれを選択して右クリックでコンテキストメニューを開き、[Run As]-[JUnit Test]を選択してJUnitを走らせてみると、テストが成功すると思います。

それでは、Serviceを利用するアプリケーションを作りましょう。

[File]-[New]-[Class]メニューでMain.javaを生成して、下記のように入力します。

package jp.org.tomotaro;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Component;

@Component
public class Main {
	@Autowired
	private Service service;

	public void sayHello() {
		System.out.println(service.getMessage());
	}
	
	public static void main(String[] args) {
		ApplicationContext appContext = 
				new ClassPathXmlApplicationContext("classpath:./META-INF/spring/app-context.xml");
		Main main = appContext.getBean(Main.class);
		main.sayHello();
	}
}

mainメソッドでは、app-context.xmlを読み込んでApplicationContextを生成し、MainクラスのBeanを取得してsayHelloメソッドを呼び出しています。
sayHelloメソッドでは@Autowiredアノテーションで自動的にインジェクトされたServiceインタフェース実装オブジェクトのgetMessageメソッドで取得したメッセージをコンソールに表示しています。
app-context.xmlでBeanのスキャン対象を「jp.org.tomotaro」にしているので、serviceにはExampleServiceのインスタンスが生成・挿入されます。

実行してみると、コンソールに「Hello world!」と無事表示されました。


しかし、mainメソッドに

System.out.println("Hello world!");

と1行書くだけのプログラムと見た目の動作自体は変わりませんが、なぜこんな回りくどいことをするんでしょうか?

以下のようなjp.org.tomotaro.stub.ServiceStub.javaを作ってみましょう。

package jp.org.tomotaro.stub;

import jp.org.tomotaro.Service;

import org.springframework.stereotype.Component;

@Component
public class ServiceStub implements Service {
	public String getMessage() {
		return "This is a Stub of Service.";
	}
}

そして、app-context.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"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">

	<description>Example configuration to get you started.</description>

	<context:component-scan base-package="jp.org.tomotaro.stub" />
	<bean id="main" class="jp.org.tomotaro.Main" />

</beans>

Beanの検索対象を「jp.org.tomotaro.stub」に変更しました。
しかし、これだとMainクラスのBeanが検索できないので、beanタグを追加しました。

実行してみると、コンソールに「This is a Stub of Service.」と表示されました。

mainメソッドに直接System.out.println(...);と書いていると、プログラムそのものを修正する必要がありますが、DIを利用すると設定だけで実装を切り替えることが出来ます。
単体試験時にはDAOをスタブに切り替えたいといった場面などに重宝します。

ちなみに、Beanの検索はcomponent-scanで指定したパッケージ以下のBeanを検索するようです。つまり、サブパッケージ内のBeanも検索されると言うことです。

ですので、この状態でcomponent-scanを「jp.org.tomotaro」に戻すと、Serviceインタフェース実装クラスが複数見つかったと言う意味の例外が発生します。

従いまして、ExampleServiceのパッケージをjp.org.tomotaro.exampleに変更し、component-scanには「jp.org.tomotaro.example」を指定するようにしました。

サンプルソースHelloWorld.zip

(次回はAOPに挑戦。つづく)

※しかし、なんでソースコードの字が小さくって、行間が開いてしまうんかなぁ???誰か解決方法を知っていたら教えてください。m(__)m