@Configuration
アノテーションを使用する
@Configuration
は、オブジェクトが Bean 定義のソースであることを示すクラスレベルのアノテーションです。@Configuration
クラスは、@Bean
アノテーション付きメソッドを介して Bean を宣言します。@Configuration
クラスでの @Bean
メソッドの呼び出しを使用して、Bean 間の依存関係を定義することもできます。一般的な導入については、基本概念: @Bean
および @Configuration
を参照してください。
Bean 間の依存関係の注入
Bean が相互に依存関係を持っている場合、その依存関係の表現は、次の例に示すように、ある Bean メソッドが別の Bean メソッドを呼び出すのと同じくらい簡単です。
Java
Kotlin
@Configuration
public class AppConfig {
@Bean
public BeanOne beanOne() {
return new BeanOne(beanTwo());
}
@Bean
public BeanTwo beanTwo() {
return new BeanTwo();
}
}
@Configuration
class AppConfig {
@Bean
fun beanOne() = BeanOne(beanTwo())
@Bean
fun beanTwo() = BeanTwo()
}
上記の例では、beanOne
はコンストラクターインジェクションを通じて beanTwo
への参照を受け取ります。
Bean 間依存関係を宣言するこの方法は、@Bean メソッドが @Configuration クラス内で宣言されている場合にのみ機能します。プレーンな @Component クラスを使用して Bean 間の依存関係を宣言することはできません。 |
ルックアップメソッドインジェクション
前述したように、ルックアップメソッドインジェクションは高度な機能であり、めったに使用しないでください。これは、シングルトンスコープの Bean がプロトタイプスコープの Bean に依存している場合に役立ちます。この型の構成に Java を使用すると、このパターンを実装するための自然な手段が提供されます。次の例は、ルックアップメソッドインジェクションの使用方法を示しています。
Java
Kotlin
public abstract class CommandManager {
public Object process(Object commandState) {
// grab a new instance of the appropriate Command interface
Command command = createCommand();
// set the state on the (hopefully brand new) Command instance
command.setState(commandState);
return command.execute();
}
// okay... but where is the implementation of this method?
protected abstract Command createCommand();
}
abstract class CommandManager {
fun process(commandState: Any): Any {
// grab a new instance of the appropriate Command interface
val command = createCommand()
// set the state on the (hopefully brand new) Command instance
command.setState(commandState)
return command.execute()
}
// okay... but where is the implementation of this method?
protected abstract fun createCommand(): Command
}
Java 構成を使用することにより、CommandManager
のサブクラスを作成できます。ここで、抽象 createCommand()
メソッドは、新しい(プロトタイプ)コマンドオブジェクトを検索するようにオーバーライドされます。次の例は、その方法を示しています。
Java
Kotlin
@Bean
@Scope("prototype")
public AsyncCommand asyncCommand() {
AsyncCommand command = new AsyncCommand();
// inject dependencies here as required
return command;
}
@Bean
public CommandManager commandManager() {
// return new anonymous implementation of CommandManager with createCommand()
// overridden to return a new prototype Command object
return new CommandManager() {
protected Command createCommand() {
return asyncCommand();
}
}
}
@Bean
@Scope("prototype")
fun asyncCommand(): AsyncCommand {
val command = AsyncCommand()
// inject dependencies here as required
return command
}
@Bean
fun commandManager(): CommandManager {
// return new anonymous implementation of CommandManager with createCommand()
// overridden to return a new prototype Command object
return object : CommandManager() {
override fun createCommand(): Command {
return asyncCommand()
}
}
}
Java ベースの構成が内部的に機能する方法に関する詳細情報
@Bean
アノテーション付きメソッドが 2 回呼び出されることを示す次の例を検討してください。
Java
Kotlin
@Configuration
public class AppConfig {
@Bean
public ClientService clientService1() {
ClientServiceImpl clientService = new ClientServiceImpl();
clientService.setClientDao(clientDao());
return clientService;
}
@Bean
public ClientService clientService2() {
ClientServiceImpl clientService = new ClientServiceImpl();
clientService.setClientDao(clientDao());
return clientService;
}
@Bean
public ClientDao clientDao() {
return new ClientDaoImpl();
}
}
@Configuration
class AppConfig {
@Bean
fun clientService1(): ClientService {
return ClientServiceImpl().apply {
clientDao = clientDao()
}
}
@Bean
fun clientService2(): ClientService {
return ClientServiceImpl().apply {
clientDao = clientDao()
}
}
@Bean
fun clientDao(): ClientDao {
return ClientDaoImpl()
}
}
clientDao()
は clientService1()
で 1 回、clientService2()
で 1 回呼び出されています。このメソッドは ClientDaoImpl
の新しいインスタンスを作成して返すため、通常は 2 つのインスタンス(各サービスに 1 つ)が必要です。それは間違いなく問題になるでしょう: Spring では、インスタンス化された Bean はデフォルトで singleton
スコープを持ちます。これが魔法の出番です。すべての @Configuration
クラスは、起動時に CGLIB
でサブクラス化されます。サブクラスでは、子メソッドは、親メソッドを呼び出して新しいインスタンスを作成する前に、キャッシュされた(スコープされた)Bean のコンテナーを最初にチェックします。
動作は、Bean のスコープに応じて異なる場合があります。ここでシングルトンについて話しています。 |
CGLIB クラスは |
CGLIB は起動時に機能を動的に追加するため、いくつかの制限があります。特に、構成クラスは final であってはなりません。ただし、構成クラスでは、 CGLIB によって課される制限を回避したい場合は、 |