コンテナーの概要

org.springframework.context.ApplicationContext インターフェースは Spring IoC コンテナーを表し、Bean のインスタンス化、構成、アセンブルを担当します。コンテナーは、構成メタデータを読み取ることで、インスタンス化、構成、アセンブルするコンポーネントに関する指示を取得します。構成メタデータは、アノテーション付きコンポーネントクラス、ファクトリメソッドを含む構成クラス、または外部 XML ファイルや Groovy スクリプトとして表すことができます。どちらの形式でも、アプリケーションとそれらのコンポーネント間の豊富な相互依存関係を構成できます。

ApplicationContext インターフェースのいくつかの実装は、コア Spring の一部です。スタンドアロンアプリケーションでは、AnnotationConfigApplicationContext (Javadoc) または ClassPathXmlApplicationContext (Javadoc) のインスタンスを作成するのが一般的です。

ほとんどのアプリケーションシナリオでは、Spring IoC コンテナーの 1 つ以上のインスタンスを作成するために明示的なユーザーコードは必要ありません。例: 単純な Web アプリケーションシナリオでは、アプリケーションの web.xml ファイル内の単純な定型 Web 記述子 XML で十分です (Web アプリケーション用の便利な ApplicationContext インスタンス化を参照)。Spring Boot シナリオでは、一般的なセットアップ規則に基づいて、アプリケーションコンテキストが暗黙的にブートストラップされます。

次の図は、Spring の機能の概要を示しています。アプリケーションクラスは構成メタデータと組み合わされ、ApplicationContext が作成および初期化された後、完全に構成された実行可能なシステムまたはアプリケーションができます。

container magic
図 1: Spring IoC コンテナー

構成メタデータ

上の図が示すように、Spring IoC コンテナーは構成メタデータの形式を使用します。この構成メタデータは、アプリケーション開発者が Spring コンテナーにアプリケーション内のコンポーネントをインスタンス化、構成、アセンブルするように指示する方法を表します。

Spring IoC コンテナー自体は、この構成メタデータが実際に書き込まれる形式から完全に切り離されています。最近では、多くの開発者が Spring アプリケーションに Java ベースの構成を選択しています。

Spring 構成は、コンテナーが管理する必要がある少なくとも 1 つの、通常は複数の Bean 定義で構成されます。Java 構成では通常、@Configuration クラス内の @Bean アノテーション付きメソッドが使用され、各メソッドは 1 つの Bean 定義に対応します。

これらの Bean 定義は、アプリケーションを構成する実際のオブジェクトに対応しています。通常、サービスレイヤーオブジェクト、リポジトリやデータアクセスオブジェクト (DAO) などの永続レイヤーオブジェクト、Web コントローラーなどのプレゼンテーションオブジェクト、JPA EntityManagerFactory などのインフラストラクチャオブジェクト、JMS キューなどを定義します。通常、ドメインオブジェクトを作成してロードするのはリポジトリとビジネスロジックの責任であるため、通常、コンテナー内にきめ細かなドメインオブジェクトを構成することはありません。

外部構成 DSL としての XML

XML ベースの構成メタデータは、これらの Bean を最上位の <beans/> 要素内の <bean/> 要素として構成します。次の例は、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
		https://www.springframework.org/schema/beans/spring-beans.xsd">

	<bean id="..." class="..."> (1) (2)
		<!-- collaborators and configuration for this bean go here -->
	</bean>

	<bean id="..." class="...">
		<!-- collaborators and configuration for this bean go here -->
	</bean>

	<!-- more bean definitions go here -->

</beans>
1id 属性は、個々の Bean 定義を識別する文字列です。
2class 属性は、Bean の型を定義し、完全修飾クラス名を使用します。

id 属性の値を使用して、コラボレートするオブジェクトを参照できます。コラボレーションオブジェクトを参照するための XML は、この例には示されていません。詳細については、依存関係を参照してください。

コンテナーをインスタンス化するには、コンテナーがローカルファイルシステム、Java CLASSPATH などのさまざまな外部リソースから構成メタデータをロードできるようにする、XML リソースファイルへの場所パスまたはパスを ClassPathXmlApplicationContext コンストラクターに提供する必要があります。

  • Java

  • Kotlin

ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");
val context = ClassPathXmlApplicationContext("services.xml", "daos.xml")

Spring の IoC コンテナーについて学習した後は、URI 構文で定義された場所から InputStream を読み取るための便利なメカニズムを提供する Spring の Resource 抽象化 ( リソースで説明されている) についてさらに知りたくなるかもしれません。特に、アプリケーションコンテキストとリソースパスに従って、Resource パスはアプリケーションコンテキストを構築するために使用されます。

次の例は、サービスレイヤーオブジェクト (services.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
		https://www.springframework.org/schema/beans/spring-beans.xsd">

	<!-- services -->

	<bean id="petStore" class="org.springframework.samples.jpetstore.services.PetStoreServiceImpl">
		<property name="accountDao" ref="accountDao"/>
		<property name="itemDao" ref="itemDao"/>
		<!-- additional collaborators and configuration for this bean go here -->
	</bean>

	<!-- more bean definitions for services go here -->

</beans>

次の例は、データアクセスオブジェクト daos.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
		https://www.springframework.org/schema/beans/spring-beans.xsd">

	<bean id="accountDao"
		class="org.springframework.samples.jpetstore.dao.jpa.JpaAccountDao">
		<!-- additional collaborators and configuration for this bean go here -->
	</bean>

	<bean id="itemDao" class="org.springframework.samples.jpetstore.dao.jpa.JpaItemDao">
		<!-- additional collaborators and configuration for this bean go here -->
	</bean>

	<!-- more bean definitions for data access objects go here -->

</beans>

前の例では、サービスレイヤーは PetStoreServiceImpl クラスと、型 JpaAccountDao および JpaItemDao の 2 つのデータアクセスオブジェクト(JPA オブジェクトリレーショナルマッピング標準に基づく)で構成されています。property name エレメントは JavaBean プロパティの名前を参照し、ref エレメントは別の Bean 定義の名前を参照します。id 要素と ref 要素の間のこのリンケージは、コラボレーションするオブジェクト間の依存関係を表します。オブジェクトの依存関係の構成の詳細については、依存関係を参照してください。

XML ベースの構成メタデータの作成

Bean 定義が複数の XML ファイルにまたがっていると便利です。多くの場合、個々の XML 構成ファイルは、アーキテクチャ内の論理層またはモジュールを表します。

ClassPathXmlApplicationContext コンストラクターを使用して、XML フラグメントから Bean 定義をロードできます。このコンストラクターは、前のセクションで示したように、複数の Resource の場所を取ります。または、<import/> 要素の 1 つ以上の出現を使用して、別のファイルから Bean 定義をロードします。次の例は、その方法を示しています。

<beans>
	<import resource="services.xml"/>
	<import resource="resources/messageSource.xml"/>
	<import resource="/resources/themeSource.xml"/>

	<bean id="bean1" class="..."/>
	<bean id="bean2" class="..."/>
</beans>

前の例では、外部 Bean 定義は、services.xmlmessageSource.xmlthemeSource.xml の 3 つのファイルからロードされます。すべてのロケーションパスは、インポートを実行する定義ファイルに関連しているため、services.xml はインポートを実行するファイルと同じディレクトリまたはクラスパスの場所にある必要があり、messageSource.xml および themeSource.xml はインポートファイルの場所の resources の場所にある必要があります。ご覧のとおり、先頭のスラッシュは無視されます。ただし、これらのパスは相対的なものであるため、スラッシュをまったく使用しない方が適切です。Spring スキーマによれば、インポートされるファイルの内容は、最上位の <beans/> 要素を含め、有効な XML Bean 定義である必要があります。

相対パス "../" を使用して親ディレクトリのファイルを参照することは可能ですが、推奨されません。これを行うと、現在のアプリケーションの外部にあるファイルに依存関係が作成されます。特に、この参照は classpath: URL(たとえば classpath:../services.xml)には推奨されません。この場合、ランタイム解決プロセスは「最も近い」クラスパスルートを選択し、その親ディレクトリを調べます。クラスパス構成の変更により、別の誤ったディレクトリが選択される場合があります。

相対パスの代わりに、たとえば file:C:/config/services.xml または classpath:/config/services.xml のような完全修飾リソースの場所を常に使用できます。ただし、アプリケーションの構成を特定の絶対ロケーションに結合していることに注意してください。一般に、このような絶対的な場所に対しては、たとえば、実行時に JVM システムプロパティに対して解決される "${ … }" プレースホルダーを介した間接性を維持することが望ましいです。

ネームスペース自体がインポートディレクティブ機能を提供します。context および util 名前空間など、Spring が提供する XML 名前空間の選択では、プレーンな Bean 定義を超えるさらなる構成機能を利用できます。

Groovy Bean 定義 DSL

外部化された設定メタデータのさらなる例として、Grails フレームワークで知られているように、Bean 定義は Spring の Groovy Bean Definition DSL でも表現できます。通常、このような設定は、次の例に示す構造を持つ ".groovy" ファイルに存在します。

beans {
	dataSource(BasicDataSource) {
		driverClassName = "org.hsqldb.jdbcDriver"
		url = "jdbc:hsqldb:mem:grailsDB"
		username = "sa"
		password = ""
		settings = [mynew:"setting"]
	}
	sessionFactory(SessionFactory) {
		dataSource = dataSource
	}
	myService(MyService) {
		nestedBean = { AnotherBean bean ->
			dataSource = dataSource
		}
	}
}

この構成スタイルは、XML Bean 定義とほぼ同等であり、Spring の XML 構成名前空間もサポートしています。また、importBeans ディレクティブを介して XML Bean 定義ファイルをインポートすることもできます。

コンテナーの使用

ApplicationContext は、さまざまな Bean とその依存関係のレジストリを維持することができる高度なファクトリのインターフェースです。メソッド T getBean(String name, Class<T> requiredType) を使用すると、Bean のインスタンスを取得できます。

ApplicationContext では、次の例に示すように、Bean 定義を読み取ってそれらにアクセスできます。

  • Java

  • Kotlin

// create and configure beans
ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");

// retrieve configured instance
PetStoreService service = context.getBean("petStore", PetStoreService.class);

// use configured instance
List<String> userList = service.getUsernameList();
   import org.springframework.beans.factory.getBean

// create and configure beans
   val context = ClassPathXmlApplicationContext("services.xml", "daos.xml")

   // retrieve configured instance
   val service = context.getBean<PetStoreService>("petStore")

   // use configured instance
   var userList = service.getUsernameList()

Groovy 構成では、ブートストラップは非常に似ています。Groovy 対応の異なるコンテキスト実装クラスがあります(ただし、XML Bean 定義も理解します)。次の例は、Groovy 構成を示しています。

  • Java

  • Kotlin

ApplicationContext context = new GenericGroovyApplicationContext("services.groovy", "daos.groovy");
val context = GenericGroovyApplicationContext("services.groovy", "daos.groovy")

最も柔軟なバリアントは、次の例に示すように、リーダーデリゲートと組み合わせた GenericApplicationContext です。たとえば、XML ファイルの XmlBeanDefinitionReader です。

  • Java

  • Kotlin

GenericApplicationContext context = new GenericApplicationContext();
new XmlBeanDefinitionReader(context).loadBeanDefinitions("services.xml", "daos.xml");
context.refresh();
val context = GenericApplicationContext()
XmlBeanDefinitionReader(context).loadBeanDefinitions("services.xml", "daos.xml")
context.refresh()

次の例に示すように、Groovy ファイルに GroovyBeanDefinitionReader を使用することもできます。

  • Java

  • Kotlin

GenericApplicationContext context = new GenericApplicationContext();
new GroovyBeanDefinitionReader(context).loadBeanDefinitions("services.groovy", "daos.groovy");
context.refresh();
val context = GenericApplicationContext()
GroovyBeanDefinitionReader(context).loadBeanDefinitions("services.groovy", "daos.groovy")
context.refresh()

同じリーダーデリゲートを同じ ApplicationContext で組み合わせて、さまざまな構成ソースから Bean 定義を読み取ることができます。

その後、getBean を使用して、Bean のインスタンスを取得できます。ApplicationContext インターフェースには、Bean を取得するためのその他のメソッドがいくつかありますが、理想的には、アプリケーションコードで Bean を使用しないでください。実際、アプリケーションコードには getBean() メソッドをまったく呼び出さないようにし、Spring API にまったく依存しないようにします。例: Spring の Web フレームワークとの統合は、コントローラーや JSF 管理の Bean などのさまざまな Web フレームワークコンポーネントへの依存性注入を提供し、メタデータ(オートワイヤーアノテーションなど)を通じて特定の Bean への依存性を宣言できます。