依存関係と構成の詳細

前のセクションで説明したように、Bean プロパティとコンストラクター引数は、他のマネージド Bean (コラボレーター) への参照として、またはインラインで定義された値として定義できます。Spring の XML ベースの構成メタデータは、この目的のために、<property/> 要素および <constructor-arg/> 要素内のサブ要素型をサポートします。

ストレート値 (プリミティブ、文字列など)

<property/> 要素の value 属性は、プロパティまたはコンストラクター引数を人間が判読できる文字列表現として指定します。Spring の変換サービスは、これらの値を String からプロパティまたは引数の実際の型に変換するために使用されます。次の例は、設定されるさまざまな値を示しています。

<bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
	<!-- results in a setDriverClassName(String) call -->
	<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
	<property name="url" value="jdbc:mysql://localhost:3306/mydb"/>
	<property name="username" value="root"/>
	<property name="password" value="misterkaoli"/>
</bean>

次の例では、さらに簡潔な XML 構成に p-namespace を使用しています。

<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:p="http://www.springframework.org/schema/p"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
	https://www.springframework.org/schema/beans/spring-beans.xsd">

	<bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource"
		destroy-method="close"
		p:driverClassName="com.mysql.jdbc.Driver"
		p:url="jdbc:mysql://localhost:3306/mydb"
		p:username="root"
		p:password="misterkaoli"/>

</beans>

上記の XML はより簡潔です。ただし、Bean 定義を作成するときにプロパティの自動補完をサポートする IDE(Pleiades All in One (JDK, STS, Lombok 付属) または Eclipse 用 Spring Tools (英語) IntelliJ IDEA (英語) など)を使用しない限り、設計時ではなく実行時に型ミスが検出されます。このような IDE の支援を強くお勧めします。

次のように、java.util.Properties インスタンスを構成することもできます。

<bean id="mappings"
	class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">

	<!-- typed as a java.util.Properties -->
	<property name="properties">
		<value>
			jdbc.driver.className=com.mysql.jdbc.Driver
			jdbc.url=jdbc:mysql://localhost:3306/mydb
		</value>
	</property>
</bean>

Spring コンテナーは、JavaBeans PropertyEditor メカニズムを使用して、<value/> エレメント内のテキストを java.util.Properties インスタンスに変換します。これは便利なショートカットであり、Spring チームが value 属性スタイルよりもネストされた <value/> 要素の使用を好む数少ない場所の 1 つです。

idref 要素

idref 要素は、コンテナー内の別の Bean の id (文字列値 - 参照ではない)を <constructor-arg/> または <property/> 要素に渡すための単なるエラー防止方法です。次の例は、その使用方法を示しています。

<bean id="theTargetBean" class="..."/>

<bean id="theClientBean" class="...">
	<property name="targetName">
		<idref bean="theTargetBean"/>
	</property>
</bean>

上記の Bean 定義スニペットは、次のスニペットと(実行時に)まったく同じです。

<bean id="theTargetBean" class="..." />

<bean id="theClientBean" class="...">
	<property name="targetName" ref="theTargetBean"/>
</bean>

idref タグを使用すると、参照される Bean という名前が実際に存在するかどうかをコンテナーが デプロイ時に検証できるため、最初の形式が 2 番目の形式よりも推奨されます。2 番目のバリエーションでは、client Bean の targetName プロパティに渡される値に対して検証は実行されません。型ミスは、client Bean が実際にインスタンス化されるときにのみ発見されます (おそらく致命的な結果を伴います)。client Bean がプロトタイプ Bean である場合、この型ミスとその結果生じる例外は、コンテナーがデプロイされてからかなり経ってから初めて発見される可能性があります。

idref エレメントの local 属性は、通常の bean 参照を超える値を提供しないため、4.0 Bean XSD ではサポートされなくなりました。4.0 スキーマにアップグレードするときに、既存の idref local 参照を idref bean に変更します。

<idref/> 要素が価値をもたらす一般的な場所(少なくとも Spring 2.0 より前のバージョン)は、ProxyFactoryBean Bean 定義の AOP インターセプターの構成にあります。インターセプター名を指定するときに <idref/> 要素を使用すると、インターセプター ID のスペルミスを防ぐことができます。

他の Bean への参照 (コラボレーター)

ref 要素は、<constructor-arg/> または <property/> 定義要素内の最後の要素です。ここでは、Bean の指定されたプロパティの値を、コンテナーによって管理される別の Bean(コラボレーター)への参照に設定します。参照される Bean は、プロパティが設定される Bean の依存関係であり、プロパティが設定される前に必要に応じて初期化されます。(コラボレーターがシングルトン Bean である場合、コンテナーによってすでに初期化されている可能性があります)すべての参照は、最終的には別のオブジェクトへの参照です。スコープと検証は、bean 属性または parent 属性を介して他のオブジェクトの ID または名前を指定するかどうかによって異なります。

<ref/> タグの bean 属性を介してターゲット Bean を指定するのが最も一般的な形式であり、同じ XML ファイル内にあるかどうかに関係なく、同じコンテナーまたは親コンテナー内の Bean への参照を作成できます。bean 属性の値は、ターゲット Bean の id 属性と同じでも、ターゲット Bean の name 属性の値の 1 つと同じでもかまいません。次の例は、ref 要素の使用方法を示しています。

<ref bean="someBean"/>

parent 属性を介してターゲット Bean を指定すると、現在のコンテナーの親コンテナーにある Bean への参照が作成されます。parent 属性の値は、ターゲット Bean の id 属性またはターゲット Bean の name 属性の値のいずれかと同じである場合があります。ターゲット Bean は、現在のコンテナーの親コンテナーに存在する必要があります。この Bean 参照バリアントは、主にコンテナーの階層があり、親 Bean と同じ名前のプロキシで親コンテナー内の既存の Bean をラップする場合に使用する必要があります。次のリストのペアは、parent 属性の使用方法を示しています。

<!-- in the parent context -->
<bean id="accountService" class="com.something.SimpleAccountService">
	<!-- insert dependencies as required here -->
</bean>
<!-- in the child (descendant) context -->
<bean id="accountService" <!-- bean name is the same as the parent bean -->
	class="org.springframework.aop.framework.ProxyFactoryBean">
	<property name="target">
		<ref parent="accountService"/> <!-- notice how we refer to the parent bean -->
	</property>
	<!-- insert other configuration and dependencies as required here -->
</bean>
ref エレメントの local 属性は、通常の bean 参照を超える値を提供しないため、4.0 Bean XSD ではサポートされなくなりました。4.0 スキーマにアップグレードするときに、既存の ref local 参照を ref bean に変更します。

インナー bean

<property/> または <constructor-arg/> 要素内の <bean/> 要素は、次の例に示すように、内部 Bean を定義します。

<bean id="outer" class="...">
	<!-- instead of using a reference to a target bean, simply define the target bean inline -->
	<property name="target">
		<bean class="com.example.Person"> <!-- this is the inner bean -->
			<property name="name" value="Fiona Apple"/>
			<property name="age" value="25"/>
		</bean>
	</property>
</bean>

内部 Bean 定義には、定義済みの ID または名前は必要ありません。指定されている場合、コンテナーはそのような値を識別子として使用しません。コンテナーは、作成時に scope フラグも無視します。これは、内部 Bean は常に匿名であり、常に外部 Bean で作成されるためです。インナー Bean に独立してアクセスしたり、内包する Bean 以外のコラボレーション Bean に注入したりすることはできません。

コーナーケースとして、たとえばシングルトン Bean に含まれるリクエストスコープの内部 Bean の場合、カスタムスコープから破棄コールバックを受け取ることができます。内側の Bean インスタンスの作成は、含まれる Bean に関連付けられていますが、破棄コールバックにより、リクエストスコープのライフサイクルに参加できます。これは一般的なシナリオではありません。通常、内部 Bean は、含まれる Bean のスコープを単に共有します。

コレクション

<list/><set/><map/><props/> 要素は、Java Collection 型 ListSetMapProperties のプロパティと引数をそれぞれ設定します。次の例は、それらの使用方法を示しています。

<bean id="moreComplexObject" class="example.ComplexObject">
	<!-- results in a setAdminEmails(java.util.Properties) call -->
	<property name="adminEmails">
		<props>
			<prop key="administrator">[email protected] (英語)  </prop>
			<prop key="support">[email protected] (英語)  </prop>
			<prop key="development">[email protected] (英語)  </prop>
		</props>
	</property>
	<!-- results in a setSomeList(java.util.List) call -->
	<property name="someList">
		<list>
			<value>a list element followed by a reference</value>
			<ref bean="myDataSource" />
		</list>
	</property>
	<!-- results in a setSomeMap(java.util.Map) call -->
	<property name="someMap">
		<map>
			<entry key="an entry" value="just some string"/>
			<entry key="a ref" value-ref="myDataSource"/>
		</map>
	</property>
	<!-- results in a setSomeSet(java.util.Set) call -->
	<property name="someSet">
		<set>
			<value>just some string</value>
			<ref bean="myDataSource" />
		</set>
	</property>
</bean>

マップキーまたは値の値、または設定値は、次の要素のいずれかです。

bean | ref | idref | list | set | map | props | value | null

コレクションのマージ

Spring コンテナーは、コレクションのマージもサポートしています。アプリケーション開発者は、親 <list/><map/><set/> または <props/> 要素を定義し、子 <list/><map/><set/> または <props/> 要素が親コレクションから値を継承およびオーバーライドするようにできます。つまり、子コレクションの値は、親コレクションと子コレクションの要素をマージした結果であり、子コレクションの要素は親コレクションで指定された値をオーバーライドします。

マージに関するこのセクションでは、親子 Bean のメカニズムについて説明します。親 Bean と子 Bean 定義を持つリーダー未知 は、続行する前に関連するセクションを読むことをお勧めします。

次の例は、コレクションのマージを示しています。

<beans>
	<bean id="parent" abstract="true" class="example.ComplexObject">
		<property name="adminEmails">
			<props>
				<prop key="administrator">[email protected] (英語)  </prop>
				<prop key="support">[email protected] (英語)  </prop>
			</props>
		</property>
	</bean>
	<bean id="child" parent="parent">
		<property name="adminEmails">
			<!-- the merge is specified on the child collection definition -->
			<props merge="true">
				<prop key="sales">[email protected] (英語)  </prop>
				<prop key="support">[email protected] (英語)  </prop>
			</props>
		</property>
	</bean>
<beans>

child Bean 定義の adminEmails プロパティの <props/> 要素で merge=true 属性が使用されていることに注意してください。child Bean がコンテナーによって解決およびインスタンス化されると、結果のインスタンスには、子の adminEmails コレクションを親の adminEmails コレクションとマージした結果を含む adminEmailsProperties コレクションが含まれます。次のリストは結果を示しています。

子 Properties コレクションの値セットは親 <props/> からすべてのプロパティ要素を継承し、support 値の子の値は親コレクションの値をオーバーライドします。

このマージ動作は、<list/><map/><set/> コレクション型と同様に適用されます。<list/> エレメントの特定のケースでは、List コレクション・型に関連付けられたセマンティクス(つまり、ordered 値のコレクションの概念)が維持されます。親の値は、子リストのすべての値の前にあります。MapSetProperties コレクション型の場合、順序はありません。コンテナーが内部で使用する関連する MapSetProperties 実装型の基礎となるコレクション・型には、順序付けのセマンティクスは有効ではありません。

コレクションのマージの制限

異なるコレクション型(Map と List など)をマージすることはできません。そうしようとすると、適切な Exception がスローされます。merge 属性は、下位の継承された子定義で指定する必要があります。親コレクション定義で merge 属性を指定することは冗長であり、目的のマージにはなりません。

強く型付けされたコレクション

ジェネリクス型に対する Java のサポートのおかげで、強く型付けされたコレクションを使用できます。つまり、(たとえば) String 要素のみを含むことができるように Collection 型を宣言することができます。Spring を使用して強い型の Collection を Bean に依存性注入する場合は、Spring の型変換サポートを利用して、強い型の Collection インスタンスの要素を適切な型に変換してからに追加することができます。Collection。次の Java クラスと Bean 定義は、その方法を示しています。

  • Java

  • Kotlin

public class SomeClass {

	private Map<String, Float> accounts;

	public void setAccounts(Map<String, Float> accounts) {
		this.accounts = accounts;
	}
}
class SomeClass {
	lateinit var accounts: Map<String, Float>
}
<beans>
	<bean id="something" class="x.y.SomeClass">
		<property name="accounts">
			<map>
				<entry key="one" value="9.99"/>
				<entry key="two" value="2.75"/>
				<entry key="six" value="3.99"/>
			</map>
		</property>
	</bean>
</beans>

something Bean の accounts プロパティが注入用に準備されると、強く型付けされた Map<String, Float> の要素型に関する一般的な情報がリフレクションによって利用可能になります。Spring の型変換インフラストラクチャは、さまざまな値要素を Float 型として認識し、文字列値(9.992.753.99)が実際の Float 型に変換されます。

NULL および空の文字列値

Spring は、プロパティなどの空の引数を空の Strings として扱います。次の XML ベースの構成メタデータスニペットは、email プロパティを空の String 値("")に設定します。

<bean class="ExampleBean">
	<property name="email" value=""/>
</bean>

上記の例は、次の Java コードと同等です。

  • Java

  • Kotlin

exampleBean.setEmail("");
exampleBean.email = ""

<null/> 要素は null 値を処理します。次のリストに例を示します。

<bean class="ExampleBean">
	<property name="email">
		<null/>
	</property>
</bean>

上記の構成は、次の Java コードと同等です。

  • Java

  • Kotlin

exampleBean.setEmail(null);
exampleBean.email = null

p-namespace を使用した XML ショートカット

p- 名前空間では、ネストされた <property/> 要素の代わりに bean 要素の属性を使用して、プロパティ値をコラボレーションする Bean、またはその両方を記述することができます。

Spring は、XML スキーマ定義に基づく、名前空間を使用した拡張可能な構成形式をサポートします。この章で説明する beans 構成形式は、XML スキーマドキュメントで定義されます。ただし、p 名前空間は XSD ファイル内で定義されておらず、Spring のコア内にのみ存在します。

次の例は、同じ結果に解決される 2 つの XML スニペット(1 つ目は標準 XML 形式を使用し、2 つ目は p-namespace を使用)を示しています。

<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:p="http://www.springframework.org/schema/p"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
		https://www.springframework.org/schema/beans/spring-beans.xsd">

	<bean name="classic" class="com.example.ExampleBean">
		<property name="email" value="[email protected] (英語)  "/>
	</bean>

	<bean name="p-namespace" class="com.example.ExampleBean"
		p:email="[email protected] (英語)  "/>
</beans>

この例は、Bean 定義の email と呼ばれる p 名前空間の属性を示しています。これは、Spring にプロパティ宣言を含めるように指示します。前述したように、p-namespace にはスキーマ定義がないため、属性の名前をプロパティ名に設定できます。

次の例には、さらに 2 つの Bean 定義が含まれており、両方とも別の Bean への参照を持っています。

<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:p="http://www.springframework.org/schema/p"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
		https://www.springframework.org/schema/beans/spring-beans.xsd">

	<bean name="john-classic" class="com.example.Person">
		<property name="name" value="John Doe"/>
		<property name="spouse" ref="jane"/>
	</bean>

	<bean name="john-modern"
		class="com.example.Person"
		p:name="John Doe"
		p:spouse-ref="jane"/>

	<bean name="jane" class="com.example.Person">
		<property name="name" value="Jane Doe"/>
	</bean>
</beans>

この例には、p-namespace を使用したプロパティ値だけでなく、プロパティ参照を宣言するための特別な形式も含まれています。最初の Bean 定義では <property name="spouse" ref="jane"/> を使用して Bean john から Bean jane への参照を作成しますが、2 番目の Bean 定義では p:spouse-ref="jane" を属性として使用してまったく同じことを行います。この場合、spouse はプロパティ名ですが、-ref 部分は、これがストレート値ではなく、別の Bean への参照であることを示しています。

p-namespace は、標準の XML 形式ほど柔軟ではありません。例: プロパティ参照を宣言する形式は、Ref で終わるプロパティと衝突しますが、標準の XML 形式は衝突しません。3 つのアプローチすべてを同時に使用する XML ドキュメントを作成しないように、アプローチを慎重に選択し、チームメンバーに伝えることをお勧めします。

c-namespace を使用した XML ショートカット

p-namespace を使用した XML ショートカットと同様に、Spring 3.1 で導入された c-namespace では、ネストされた constructor-arg 要素ではなく、コンストラクター引数を構成するためのインライン属性を使用できます。

次の例では、c: 名前空間を使用して、コンストラクターベースの依存性注入からと同じことを行います。

<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:c="http://www.springframework.org/schema/c"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
		https://www.springframework.org/schema/beans/spring-beans.xsd">

	<bean id="beanTwo" class="x.y.ThingTwo"/>
	<bean id="beanThree" class="x.y.ThingThree"/>

	<!-- traditional declaration with optional argument names -->
	<bean id="beanOne" class="x.y.ThingOne">
		<constructor-arg name="thingTwo" ref="beanTwo"/>
		<constructor-arg name="thingThree" ref="beanThree"/>
		<constructor-arg name="email" value="[email protected] (英語)  "/>
	</bean>

	<!-- c-namespace declaration with argument names -->
	<bean id="beanOne" class="x.y.ThingOne" c:thingTwo-ref="beanTwo"
		c:thingThree-ref="beanThree" c:email="[email protected] (英語)  "/>

</beans>

c: 名前空間は、名前でコンストラクター引数を設定するために、p: の名前空間(Bean 参照の末尾の -ref)と同じ規則を使用します。同様に、XSD スキーマ(Spring コア内に存在する)で定義されていない場合でも、XML ファイルで宣言する必要があります。

コンストラクター引数名が使用できないまれなケース (通常、バイトコードが -parameters フラグなしでコンパイルされた場合) では、次のように引数インデックスにフォールバックできます。

<!-- c-namespace index declaration -->
<bean id="beanOne" class="x.y.ThingOne" c:_0-ref="beanTwo" c:_1-ref="beanThree"
	c:_2="[email protected] (英語)  "/>
XML 文法により、XML 属性名は数字で始めることができないため(インデックスの表記法では先頭の _ の存在が必要です(一部の IDE では許可されていますが)。対応するインデックス表記は <constructor-arg> 要素にも使用できますが、通常は宣言の単純な順序で十分なので一般的には使用されません。

実際には、コンストラクター解決メカニズムは引数の照合に非常に効率的であるため、本当に必要な場合を除いて、構成全体で名前表記を使用することをお勧めします。

複合プロパティ名

最終プロパティ名を除くパスのすべてのコンポーネントが null でない限り、Bean プロパティを設定するときに複合またはネストされたプロパティ名を使用できます。以下の Bean 定義を考慮してください。

<bean id="something" class="things.ThingOne">
	<property name="fred.bob.sammy" value="123" />
</bean>

something Bean には fred プロパティがあり、bob プロパティには sammy プロパティがあり、その最終 sammy プロパティには 123 の値が設定されています。これが機能するためには、Bean の作成後に something の fred プロパティと fred の bob プロパティが null であってはなりません。そうでない場合、NullPointerException がスローされます。