3.自動的にDIする方法

概要

Springでは、明示的にApplicationContextファイルにbeanを記述するだけでなく、自動的に取り込む方法が用意されています。

この方法を使うと、クラス名をbean名にして自動的にDIすることもできます。

そうすると記述の手間が省けるので、クラス名の命名規則さえ決めてしまえば管理も楽になります。

この記事では自動的にDIする方法を見て行きます。

自動的にbeanをApplicationContextに取り込む

【ApplicationContext.xmlの記述サンプル】

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

xmlns:p="http://www.springframework.org/schema/p"

xmlns:aop ="http://www.springframework.org/schema/aop"

xmlns:util="http://www.springframework.org/schema/util"

xmlns:context="http://www.springframework.org/schema/context"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://www.springframework.org/schema/aop

http://www.springframework.org/schema/aop/spring-aop-2.5.xsd

http://www.springframework.org/schema/util

http://www.springframework.org/schema/util/spring-util-2.5.xsd

http://www.springframework.org/schema/beans

http://www.springframework.org/schema/beans/spring-beans-2.5.xsd

http://www.springframework.org/schema/context

http://www.springframework.org/schema/context/spring-context-2.5.xsd">

<context:component-scan base-package="com.my." annotation-config="true">

<context:include-filter type="regex" expression=".*Action"/>

</context:component-scan>

</beans>

component-scanタグを使用すると、ロードされたクラスの中から、指定のクラスが自動でDIコンテナにロードされます。

【base-package属性】

クラスの指定の仕方はいくつか用意されています。

まず、base-package属性ですが、パッケージ名のプレフィックスを指定できます。

上記の例で言うと、com.my.から始まるパッケージ内のクラスを全てDIコンテナにロードします。

カンマ区切りで複数指定することもできます。

【annotation-config属性】

Springでは、setterなどに@Resourceのようなアノテーションを設定することもできます。

アノテーションはannotation-config属性をtrueにすると働きます。@Autowiredや@Resourceなどのアノテーションは、

自動でsetterに値を設定してくれます。(DIしてくれます)

これについては、下の方で記述していますのでそちらを参照ください。

デフォルトは、trueです。

【include-filter/exclude-filter】

include-filter/exclude-filterタグは、base-packageで指定したパッケージ内のクラスをさらに絞るために使用されます。

includeでは含めるクラス、excludeでは除外するクラスを指定します。

指定の仕方はtype属性で決めます。

type属性に指定できるタイプとその内容は以下の一覧を参照ください。

【filterのtype一覧】

自動的にContext内のbeanに値を設定する(XML設定によるAutowire)

Autowireとは

Autowireとは、自動的にクラスのプロパティ(setter)や、メンバ変数に値を設定する機能です。

どのプロパティにどのbeanを設定するかは、アノテーションで指定することができます。

【Autowireの記述例】

@Resource

public void setCount(int count) {

this.count = count;

}

@Autowired

public void setMemberDao(MemberDao memberDao) {

this.memberDao = memberDao;

}

上記のように、アノテーションを記述するだけで、自動的に設定されます。setterだけではなく、メンバ変数にもアノテーションを設定できます。

ただし、いずれにしてもアノテーションを有効にすることをSpringに伝えなければなりません。

その主な方法は以下のとおりです。

【アノテーションを有効にする方法】

・conponent-scanタグを記述する方法。annotation-config属性をtrueにすると有効になります。

・<context:annotation-config />タグをXML内に記述する方法。これだけで、beanすべてにアノテーションが有効になります。

@Autowiredアノテーション

このアノテーションは、DIコンテナの中からクラスまたはインターフェースの派生クラスになっているbeanを検索して値を設定します。

beanのidは無視されます。

例えば上記の例では、MemberDaoクラスかその派生クラスをDIコンテナ内を探します。

見つかったbeanがsetされることになります。

もし派生クラスが複数見つかった場合はエラーが発生しますので、設定ファイル中に複数存在しないように記述しなければなりません。

実は、これをbean名で絞ることもできます。以下のように@Qualifierを追記します。

@Autowired

@Qualifier("memberDao")

@Resourceアノテーション

このアノテーションは、プロパティ名、メンバ変数名を見て、同じbean名のオブジェクトをsetします。

上記の例では、countというbean名を探し出してsetします。

自動的に外部オブジェクトに値を設定する(プログラムによるAutowire)

上記ではXML設定にbeanを記述することで自動的に値を設定する例をみました。

ここでは、XML内には存在しない、外部のオブジェクトに、XMLで記述したbeanをセットする例を見てみます。

この機能は、共通の基盤を作る場合などに特に有効かと思います。

【プログラムによるAutowireのサンプル】

public class Test {

MemberDao memberDao;

public static void main(String[] args) throws Exception {

String contextFile = args[0];

FileSystemXmlApplicationContext context = new FileSystemXmlApplicationContext(contextFile);

try{

Test test = new Test();

context.getAutowireCapableBeanFactory().autowireBeanProperties(test,

AutowireCapableBeanFactory.AUTOWIRE_BY_NAME, false);

test.memberDao.update();

}finally{

context.close();

}

}

//セッター

public void setMemberDao(MemberDao memberDao){

this.memberDao = memberDao;

}

}

【applicationContext.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="memberDao" class="com.my.MemberDaoImpl">

</bean>

</beans>

まず、このTestクラスの動作ですが、mainの起動引数に applicationContext.xmlの設定ファイルのパスを渡します。

applicationContext.xmlの設定ファイルには、当然ながらmemberDaoという名前でbeanが設定されている必要があります。

【Autowireの動作】

プログラムからAutowireを行うには、上記のようにautowireBeanProperties()メソッドを使用します。

<1つ目の引数>

メソッドの1つ目の引数には、autowireされるオブジェクトを指定します。

上記の場合は、newしたTestクラスを指定しています。

このクラスにはmemberDaoプロパティ(setter)が存在していますので、これがautowireの対象になります。

<2つ目の引数>

このとき、どのようにsetするbeanを検索するかを指定します。(上記例では、AUTOWIRE_BY_NAME)

BY_NAMEは、アノテーションの@Resourceのようにプロパティ名(setter名)と同じbean名を検索して設定します。

bean名で検索する他、@Autowiredのようにクラスやインターフェースで検索する方法が存在します(AUTOWIRE_BY_TYPE)。

プログラムによるAutowireでは、メンバ変数に対してはAutowireできず、setterによるAutowireのみが提供されているようです。

上記では、setMemberDaoしかありませんので、このsetterに対してmemberDaoという名前のbeanを探して設定します。

<3つ目の引数>

autowireBeanProperties()メソッドの3つ目の引数はbooleanを指定します。

trueにすると、存在するsetterすべてにautowireしようとし、設定するbeanが見つからないプロパティがあればエラーにします。

falseにすると、beanが見つからない場合でもエラーにはしません。

通常であればmemberDaoはnullのはずですが、nullポインタ例外は発生しません。

Autowireがうまく働いているからです。

【補足】

上記のサンプルは、ApplicationContext.xmlにTestクラスのbeanを記述することで代用もできそうな気がします。

しかしサンプルの方法では、XMLファイルを引数に取るTest2という新しいクラスを作成し、全く違う動作をさせることもできます。

そうすると、XMLファイルは1つだけで、起動するTestクラスを変えるだけで様々な動きをさせることができます。

かなり幅が広がることが分かるかと思います。

Created Date: 2011/10/21