@Bean アノテーションの使用

@Bean は、メソッドレベルのアノテーションであり、XML <bean/> 要素の直接の類似物です。アノテーションは、次のような <bean/> によって提供される属性の一部をサポートします。

@Bean アノテーションは、@Configuration アノテーション付きまたは @Component アノテーション付きクラスで使用できます。

Bean の宣言

Bean を宣言するために、@Bean アノテーションを使用してメソッドにアノテーションを付けることができます。このメソッドを使用して、メソッドの戻り値として指定された型の ApplicationContext 内に Bean 定義を登録します。デフォルトでは、Bean 名はメソッド名と同じです。次の例は、@Bean メソッドの宣言を示しています。

  • Java

  • Kotlin

@Configuration
public class AppConfig {

	@Bean
	public TransferServiceImpl transferService() {
		return new TransferServiceImpl();
	}
}
@Configuration
class AppConfig {

	@Bean
	fun transferService() = TransferServiceImpl()
}

上記の構成は、次の Spring XML とまったく同じです。

<beans>
	<bean id="transferService" class="com.acme.TransferServiceImpl"/>
</beans>

次のテキストイメージに示すように、両方の宣言により、transferService という名前の Bean が ApplicationContext で使用可能になり、型 TransferServiceImpl のオブジェクトインスタンスにバインドされます。

transferService -> com.acme.TransferServiceImpl

デフォルトのメソッドを使用して Bean を定義することもできます。これにより、デフォルトのメソッドで Bean 定義を使用してインターフェースを実装することにより、Bean 構成を構成できます。

  • Java

public interface BaseConfig {

	@Bean
	default TransferServiceImpl transferService() {
		return new TransferServiceImpl();
	}
}

@Configuration
public class AppConfig implements BaseConfig {

}

次の例に示すように、@Bean メソッドをインターフェース(または基本クラス)戻り値の型で宣言することもできます。

  • Java

  • Kotlin

@Configuration
public class AppConfig {

	@Bean
	public TransferService transferService() {
		return new TransferServiceImpl();
	}
}
@Configuration
class AppConfig {

	@Bean
	fun transferService(): TransferService {
		return TransferServiceImpl()
	}
}

ただし、これにより、事前型予測の可視性が指定されたインターフェース型(TransferService)に制限されます。次に、影響を受けるシングルトン Bean がインスタンス化された後でのみ、コンテナーに認識されるフル型(TransferServiceImpl)を使用します。遅延のないシングルトン Bean は宣言順序に従ってインスタンス化されるため、別のコンポーネントが宣言されていない型(transferService Bean がインスタンス化された後にのみ解決される @Autowired TransferServiceImpl など)によって一致しようとするタイミングに応じて、異なる型一致結果が表示される場合があります)。

宣言されたサービスインターフェースで型を一貫して参照する場合、@Bean 戻り型はその設計決定に安全に参加できます。ただし、複数のインターフェースを実装するコンポーネント、または実装型で潜在的に参照されるコンポーネントの場合、可能な限り最も具体的な戻り値の型を宣言する方が安全です(少なくとも Bean を参照するインジェクションポイントで要求される特定の)。

Bean の依存関係

@Bean アノテーション付きメソッドは、その Bean を構築するために必要な依存関係を記述する任意の数のパラメーターを持つことができます。たとえば、TransferService に AccountRepository が必要な場合、次の例に示すように、メソッドパラメーターを使用してその依存関係を具体化できます。

  • Java

  • Kotlin

@Configuration
public class AppConfig {

	@Bean
	public TransferService transferService(AccountRepository accountRepository) {
		return new TransferServiceImpl(accountRepository);
	}
}
@Configuration
class AppConfig {

	@Bean
	fun transferService(accountRepository: AccountRepository): TransferService {
		return TransferServiceImpl(accountRepository)
	}
}

解決メカニズムはコンストラクターベースの依存性注入とほぼ同じです。詳細については、関連するセクションを参照してください。

ライフサイクルコールバックの受信

@Bean アノテーションで定義されたクラスは、通常のライフサイクルコールバックをサポートし、JSR-250 の @PostConstruct および @PreDestroy アノテーションを使用できます。詳細については、JSR-250 アノテーションを参照してください。

通常の Spring ライフサイクルコールバックも完全にサポートされています。Bean が InitializingBeanDisposableBeanLifecycle を実装している場合、それぞれのメソッドはコンテナーによって呼び出されます。

*Aware インターフェースの標準セット(BeanFactoryAwareBeanNameAwareMessageSourceAwareApplicationContextAware など)も完全にサポートされています。

@Bean アノテーションは、Spring XML の init-method 属性や destroy-method 属性と同様に、任意の初期化および破棄コールバックメソッドを bean 要素に指定することをサポートします。次に例を示します。

  • Java

  • Kotlin

public class BeanOne {

	public void init() {
		// initialization logic
	}
}

public class BeanTwo {

	public void cleanup() {
		// destruction logic
	}
}

@Configuration
public class AppConfig {

	@Bean(initMethod = "init")
	public BeanOne beanOne() {
		return new BeanOne();
	}

	@Bean(destroyMethod = "cleanup")
	public BeanTwo beanTwo() {
		return new BeanTwo();
	}
}
class BeanOne {

	fun init() {
		// initialization logic
	}
}

class BeanTwo {

	fun cleanup() {
		// destruction logic
	}
}

@Configuration
class AppConfig {

	@Bean(initMethod = "init")
	fun beanOne() = BeanOne()

	@Bean(destroyMethod = "cleanup")
	fun beanTwo() = BeanTwo()
}

デフォルトでは、パブリック close または shutdown メソッドを持つ Java 構成で定義された Bean は、破棄コールバックに自動的に参加します。パブリック close または shutdown メソッドがあり、コンテナーのシャットダウン時に呼び出されたくない場合は、@Bean(destroyMethod = "") を Bean 定義に追加して、デフォルトの (inferred) モードを無効にすることができます。

そのライフサイクルはアプリケーションの外部で管理されるため、JNDI で取得するリソースに対してデフォルトでそれを行うことができます。特に、Jakarta EE アプリケーションサーバーでは問題があることが知られているため、必ず DataSource に対して実行してください。

次の例は、DataSource の自動破棄コールバックを防ぐ方法を示しています。

  • Java

  • Kotlin

@Bean(destroyMethod = "")
public DataSource dataSource() throws NamingException {
	return (DataSource) jndiTemplate.lookup("MyDS");
}
@Bean(destroyMethod = "")
fun dataSource(): DataSource {
	return jndiTemplate.lookup("MyDS") as DataSource
}

また、@Bean メソッドでは、通常、Spring の JndiTemplate または JndiLocatorDelegate ヘルパーを使用するか、JNDI InitialContext をそのまま使用して、プログラムによる JNDI ルックアップを使用しますが、JndiObjectFactoryBean バリアントは使用しません。これにより、戻り型を実際のターゲット型ではなく FactoryBean 型として宣言しなければならなくなり、ここで提供されたリソースを参照しようとする他の @Bean メソッドでの相互参照呼び出しに使用するのが困難になります。

前の例の上の例の BeanOne の場合、次の例に示すように、構築中に init() メソッドを直接呼び出すことも同様に有効です。

  • Java

  • Kotlin

@Configuration
public class AppConfig {

	@Bean
	public BeanOne beanOne() {
		BeanOne beanOne = new BeanOne();
		beanOne.init();
		return beanOne;
	}

	// ...
}
@Configuration
class AppConfig {

	@Bean
	fun beanOne() = BeanOne().apply {
		init()
	}

	// ...
}
Java で直接作業する場合、オブジェクトを使用して好きなことを行うことができ、常にコンテナーのライフサイクルに依存する必要はありません。

Bean スコープの指定

Spring には @Scope アノテーションが含まれているため、Bean のスコープを指定できます。

@Scope アノテーションの使用

@Bean アノテーションで定義された Bean に特定のスコープが必要であることを指定できます。Bean スコープセクションで指定された標準スコープのいずれかを使用できます。

デフォルトのスコープは singleton ですが、次の例に示すように、@Scope アノテーションでこれをオーバーライドできます。

  • Java

  • Kotlin

@Configuration
public class MyConfiguration {

	@Bean
	@Scope("prototype")
	public Encryptor encryptor() {
		// ...
	}
}
@Configuration
class MyConfiguration {

	@Bean
	@Scope("prototype")
	fun encryptor(): Encryptor {
		// ...
	}
}

@Scope および scoped-proxy

Spring は、スコープ付きプロキシを介してスコープ付き依存関係を操作する便利な方法を提供します。XML 構成を使用するときにこのようなプロキシを作成する最も簡単な方法は、<aop:scoped-proxy/> 要素です。@Scope アノテーションを使用して Java で Bean を構成すると、proxyMode 属性と同等のサポートが提供されます。デフォルトは ScopedProxyMode.DEFAULT です。これは通常、コンポーネントスキャン命令レベルで別のデフォルトが設定されていない限り、スコーププロキシを作成しないことを示します。ScopedProxyMode.TARGET_CLASSScopedProxyMode.INTERFACESScopedProxyMode.NO を指定できます。

Java を使用して、XML リファレンスドキュメント ( 「スコープ付きプロキシ」を参照) からスコープ付きプロキシの例を @Bean に移植すると、次のようになります。

  • Java

  • Kotlin

// an HTTP Session-scoped bean exposed as a proxy
@Bean
@SessionScope
public UserPreferences userPreferences() {
	return new UserPreferences();
}

@Bean
public Service userService() {
	UserService service = new SimpleUserService();
	// a reference to the proxied userPreferences bean
	service.setUserPreferences(userPreferences());
	return service;
}
// an HTTP Session-scoped bean exposed as a proxy
@Bean
@SessionScope
fun userPreferences() = UserPreferences()

@Bean
fun userService(): Service {
	return SimpleUserService().apply {
		// a reference to the proxied userPreferences bean
		setUserPreferences(userPreferences())
	}
}

Bean 命名のカスタマイズ

デフォルトでは、構成クラスは @Bean メソッドの名前を結果の Bean の名前として使用します。ただし、次の例に示すように、この機能は name 属性でオーバーライドできます。

  • Java

  • Kotlin

@Configuration
public class AppConfig {

	@Bean("myThing")
	public Thing thing() {
		return new Thing();
	}
}
@Configuration
class AppConfig {

	@Bean("myThing")
	fun thing() = Thing()
}

Bean エイリアス

Bean の命名で説明したように、単一の Bean に複数の名前(別名 Bean エイリアス)を付けることが望ましい場合があります。@Bean アノテーションの name 属性は、この目的のためにストリング配列を受け入れます。次の例は、Bean に複数のエイリアスを設定する方法を示しています。

  • Java

  • Kotlin

@Configuration
public class AppConfig {

	@Bean({"dataSource", "subsystemA-dataSource", "subsystemB-dataSource"})
	public DataSource dataSource() {
		// instantiate, configure and return DataSource bean...
	}
}
@Configuration
class AppConfig {

	@Bean("dataSource", "subsystemA-dataSource", "subsystemB-dataSource")
	fun dataSource(): DataSource {
		// instantiate, configure and return DataSource bean...
	}
}

Bean の説明

時々、Bean のより詳細なテキスト記述を提供すると役立つことがあります。これは、監視目的で Bean が(おそらく JMX を介して)公開されている場合に特に役立ちます。

@Bean に説明を追加するには、次の例に示すように、@Description (Javadoc) アノテーションを使用できます。

  • Java

  • Kotlin

@Configuration
public class AppConfig {

	@Bean
	@Description("Provides a basic example of a bean")
	public Thing thing() {
		return new Thing();
	}
}
@Configuration
class AppConfig {

	@Bean
	@Description("Provides a basic example of a bean")
	fun thing() = Thing()
}