目次


Java ベースの構成を使用して Spring Bean を管理する

Java ベースの構成を使用して Spring Bean を管理する方法を学ぶ

概要

よく知られているように、Spring フレームワークではコンテナー・ベースの構成を使用して IoC (Inversion of Control: 制御の反転) パターンすなわち DI (Dependency Injection: 依存性注入) パターンを実装しています。Spring では従来、アプリケーションのコンテキスト XML ファイルを使用した XML ベースの構成を使用することで Bean の依存関係を管理しています。このファイルはアプリケーションにとって外部ファイルであり、そのアプリケーションに対する Bean および Bean の依存関係に関する定義を保持しています。XML ベースの構成は使いやすくて便利ですが、Bean および Bean の依存関係を定義する方法には、「Java ベースの構成」と呼ばれる方法もあります。XML の場合とは異なり、Java ベースの構成ではプログラムによって Bean を管理することができ、そのためにはさまざまなアノテーションを使用します。この記事では、Java ベースの構成を用いた例について、XML による従来の構成方法と比較しながら説明します。従来の方法と比較することで、この Java ベースの構成についてよく理解できるようになるはずです。この記事では Java ベースの構成の基本的な使い方を以下のステップで説明します。

  • @Configuration アノテーションと @Bean アノテーションの概要
  • AnnotationConfigApplicationContext を使って構成クラスを登録する方法
  • Web アプリケーションを構成する方法
  • Bean のライフサイクル・コールバックとスコープを実装する方法

ここでは、オンライン大学の「Create Course (コース作成)」の例を取り上げます。このコース (course) 作成のプロセスでは、トピック、つまりモジュール (module) も作成し、各トピックにはさまざまな課題 (assignment) を含めることも可能です。そこで、CourseModuleAssignment という 3 つの Bean を作成します。Course Bean は Module Bean を参照し、その Module Bean は Assignment Bean への参照を保持します。

@Configuration アノテーションと @Bean アノテーションの概要

理想的なシナリオでは、アプリケーション・コンテキストを表現する XML で Bean を定義します。以下のコードは Create Course という例の Bean を定義するコンテキスト XML を示しています。

リスト 1. Bean を定義する XML
<beans>
	<bean id="course" class="demo.Course">
		<property name="module" ref="module"/>
  	</bean>
	
	<bean id="module" class="demo.Module">
		<property name="assignment" ref="assignment"/>
  	</bean>
	
	<bean id="assignment" class="demo.Assignment" />
</beans>

上記の XML は、Spring で Bean を構成する場合に作成される典型的な XML です。この XML では Course Bean を定義し、Course Bean は Module Bean を参照しています。そして、Module Bean は Assignment Bean を参照しています。ここで、この XML をやめ、この XML と等価な Java コードを作成します。上記のように規定された Bean を、Java ベースの構成を使用して定義します。この XML を、Bean を構成するためのプラットフォームとして動作する Java クラスで置き換えます。このクラスの名前を AppContext.java としましょう。以下のコードは AppContext クラスを示しています。

リスト 2. Bean の定義を含む AppContext 構成クラス
@Configuration
public class AppContext {
	@Bean
	public Course course() {
		Course course = new Course();
		course.setModule(module());
		return course;
	}

	@Bean
	public Module module() {
		Module module = new Module();
		module.setAssignment(assignment());
		return module;
	}

	@Bean
	public Assignment assignment() {
		return new Assignment();
	}
}

上記のコードを見るとわかるように、今度は Java ベースの構成の一部として、Bean がプログラムで定義されています。この場合の AppContext クラスは、先ほどの XML とまったく同じように構成クラスを表します。これは @Configuration アノテーションを使用することで実現されています。@Configuration アノテーションはこの AppContext クラスの上に配置されており、Spring コンテナーに対し、このクラスが Bean の定義と依存関係を含む構成クラスであることを伝えています。@Bean アノテーションは Bean を定義するために使われており、Bean をインスタンス化して Bean の依存関係を設定するメソッドの上に配置されています。このメソッドの名前はデフォルトで、Bean の ID、つまり名前と同じです。このメソッドの戻り型は Spring のアプリケーション・コンテキストに登録された Bean です。この Bean のセッター・メソッドを使用して依存関係を設定すると、コンテナーはそれらの依存関係を呼び出し、関連付けを行います。Java ベースの構成はアノテーション・ベースの構成と見なすこともできます。

AnnotationConfigApplicationContext を使用して構成クラスを登録する方法

XML による従来の方法では、ClassPathXmlApplicationContext クラスを使用して外部の XML コンテキスト・ファイルをロードします。しかし Java ベースの構成を使用する場合には AnnotationConfigApplicationContext クラスがあります。AnnotationConfigApplicationContext クラスは ApplicationContext インターフェースの実装の 1 つであり、アノテーションを付けられた構成クラスを登録するために使用することができます。この場合の構成クラスは @Configuration アノテーションを使って宣言された AppContext です。このクラスを登録すると、@Bean アノテーションが付けられたメソッドによって返されるすべての Bean の型も登録されます。以下のコードは AnnotationConfigApplicationContext クラスの使い方を示しています。

リスト 3. AnnotationConfigApplicationContext を使用して AppContext クラスを登録する
public static void main(String[] args) {
  ApplicationContext ctx = new AnnotationConfigApplicationContext(AppContext.class);
  Course course = ctx.getBean(Course.class);
  course.getName();
}

上記のコードを見るとわかるように、AppContext 構成クラスは AnnotationConfigApplicationContext コンストラクターに渡されることで登録されています。こうする代わりに、このコンテキスト・クラスの register メソッドを使用して AppContext 構成クラスを登録することもできます。その方法を示したものが以下のコードです。

リスト 4. AppContext クラスを登録するための別の方法
public static void main(String[] args) {
  ApplicationContext ctx = new AnnotationConfigApplicationContext();
  ctx.register(AppContext.class)
}

構成クラスを登録すると、@Bean アノテーションが付けられたメソッド名が自動的に登録され、それによってその構成クラスに対応する Bean、つまり CourseModuleAssignment も登録されます。すると、getBean メソッドを使用して当該する Bean を取得し、その Bean のビジネス・メソッドを呼び出すことができます。つまり、これを見るとわかるように、Java ベースの構成クラスの作成は非常に簡単であり、この構成クラスを Spring コンテキストに登録する方法も非常に簡単です。次のセクションでは Webアプリケーションで Java ベースの構成を使用する方法について説明します。

Webアプリケーションを構成する方法

通常、Spring Web アプリケーションを構成する場合には、Web デプロイメント記述子ファイルである web.xml の中で外部 XML コンテキスト・ファイルへのパスを指定し、XmlWebApplicationContext コンテキストを使用します。XMLWebApplicationContext は Web アプリケーションがデフォルトで使用するコンテキスト・クラスです。以下のコードに示す web.xml 内の要素は、ContextLoaderListener リスナー・クラスによってロードされる外部 XML コンテキスト・ファイルを指しています。

リスト 5. 外部 XML コンテキスト・ファイルを使用する web.xml
<web-app>
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>/WEB-INF/applicationContext.xml</param-value>
	</context-param>
	<listener>
		<listener-class>
			org.springframework.web.context.ContextLoaderListener
		</listener-class>
	</listener>
	<servlet>
	<servlet-name>sampleServlet</servlet-name>
	<servlet-class>
		org.springframework.web.servlet.DispatcherServlet
	</servlet-class>
	</servlet>

...
</web-app>

今度は、AnnotationConfigApplicationContext クラスを使用するように、上記の web.xml のコードを変更します。XmlWebApplicationContext は Spring がデフォルトで Web アプリケーションに使用するコンテキスト実装であることを思い出してください。そのため、このコンテキスト・クラスを web.xml ファイル内で明示的に指定することはありません。今度は Java ベースの構成を使用するので、Web アプリケーション用に構成する際、web.xml ファイル内で AnnotationConfigApplicationContext クラスを指定する必要があります。上記のコードを変更すると以下のようになります。

リスト 6. AnnotationConfigApplicationContext を使用するように変更された web.xml
<web-app>
	<context-param>
		<param-name>contextClass</param-name>
		<param-value>
			org.springframework.web.context.
			support.AnnotationConfigWebApplicationContext
		</param-value>
	</context-param>
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>
			demo.AppContext
		</param-value>
	</context-param>
	<listener>
		<listener-class>
			org.springframework.web.context.ContextLoaderListener
		</listener-class>
	</listener>
	<servlet>
	<servlet-name>sampleServlet</servlet-name>
	<servlet-class>
		org.springframework.web.servlet.DispatcherServlet
	</servlet-class>
	<init-param>
		<param-name>contextClass</param-name>
		<param-value>
			org.springframework.web.context.
			support.AnnotationConfigWebApplicationContext
		</param-value>
	</init-param>
	</servlet>

...
</web-app>

変更された上記の web.xml は、今度はコンテキスト・パラメーターとサーブレット要素の一部として AnnotationConfigWebApplicationContext コンテキスト・クラスを定義しています。コンテキストを構成する場所として、今度は AppContext 構成クラスが指定されています。これは簡単でした。次のセクションでは Bean のライフサイクル・コールバックとスコープの実装方法について説明します。

Bean のライフサイクル・コールバックとスコープを実装する方法

ライフサイクル・コールバック

Java ベースの構成を使用して Bean のライフサイクルも管理することができます。@BeaninitMethoddestroyMethod という 2 つの属性をサポートしており、この 2 つの属性を使用してライフサイクル・メソッドを定義することができます。ライフサイクル・メソッドは Bean がインスタンス化される時に、または破棄される直前に、コンテナーによって呼び出されます。ライフサイクル・メソッドはコンテナーに呼び出されるため、コールバック・メソッドとも呼ばれます。@Bean アノテーションによって登録される Bean は、JSR-250 の一部としての標準的な @PostConstruct アノテーションと @PreDestroy アノテーションもサポートしています。XML ベースの方法を使用して Bean を定義する場合には、Bean 要素を使用してライフサイクル・コールバック・メソッドを定義します。以下のコードは XML ベースの構成で Bean 要素を使用してコールバックを定義する場合の一般的な方法を示しています。

リスト 7. ライフサイクル・コールバックに XML ベースの方法を使用する
<bean id="course" class="demo.Course" init-method="setup" destroy-method="cleanup" >
	<property name="module" ref="module"/>
</bean>

以下に示すのは Java ベースの構成でライフサイクル・メソッドを使用する場合のコードです。

リスト 8. AppContext 構成クラスを使用して Bean のライフサイクル・メソッドを実装する
@Configuration
public class AppContext {
	@Bean(initMethod = "setup", destroyMethod = "cleanup")
	public Course course() {
		Course course = new Course();
		course.setModule(module());
		return course;
	}

	@Bean(initMethod = "setup", destroyMethod = "cleanup")
	public Module module() {
		Module module = new Module();
		module.setAssignment(assignment());
		return module;
	}
	
	...
}		
public class Course {

	private Module module;
	private String name;
	
	public Course() {
	}
	
	public void setup() {
		this.name = "M100 Pythagoras Theorems"
	}
	
	public void setModule(Module module) {
		this.module = module;
	}
	
	public void cleanup() {
		module = null;
	}
}

上記のコードでも、AppContext 構成クラスを使用しています。今度は @Bean アノテーションに initMethoddestroyMethod という 2 つの属性が追加されています。この 2 つの属性はライフサイクル・メソッドのセットアップとクリーンアップを定義しています。これらのメソッドは登録された Bean の中で実装された後、Bean が初期化される際と Bean が破棄される前にコンテナーによって呼び出されます。ここで例として取り上げた Course Bean はライフサイクル・メソッドの実装を提供しています。実装されるメソッドは setupcleanup です。同様に、これらのメソッドを Module Bean と Assignment Bean 内でも実装することができます。

Bean のスコープ

Bean のスコープは @Scope アノテーションを使って定義することができます。XML ベースの方法では Bean 要素の中で scope 要素を指定しました。

リスト 9. XML ベースの方法で Bean のスコープを定義する
<bean id="course" class="demo.Course" scope="prototype" >
	<property name="module" ref="module"/>
</bean>

以下に示すのは Java ベースの構成を使用して Bean のスコープを定義する場合のコードです。

リスト 10. AppContext 構成クラスを使用して Bean のスコープを定義する
@Configuration
public class AppContext {
	@Bean(initMethod = "setup", destroyMethod = "cleanup")
	@Scope("prototype")
	public Course course() {
		Course course = new Course();
		course.setModule(module());
		return course;
	}
	...
}

上記のコードを見るとわかるように、Java 構成クラスの中で Bean のスコープを定義する方法は非常に簡単です。上記の AppContext 構成クラスは @Scope アノテーションを使用して Course Bean の prototype スコープを定義しています。デフォルトのスコープは singleton です。

Java ベースの構成を使用してできることは数多くありますが、この記事では基本的なことに触れたにすぎません。Java ベースの構成を使用することで非常に大きなメリットがあるわけではなく、Spring で XML ベースの構成の代わりに使用できるにすぎません。フレームワークに XML を使用することを好まない人には、Java ベースの構成方法は適しています。当然ですが、欠点としては、Java クラスの構成を少しでも変更した場合にはアプリケーションを再度コンパイルする必要があることです。


ダウンロード可能なリソース


関連トピック

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=SOA and web services
ArticleID=753232
ArticleTitle=Java ベースの構成を使用して Spring Bean を管理する
publish-date=08262011