前回までに、Spring Beanの定義には @Component や @Service といったアノテーションを使うのが主流だと学びました。これは、私たちが自分で書いたクラスをBeanとして登録する最も簡単な方法です。
しかし、次のような場合は、アノテーションだけでは対応できません。
- 外部ライブラリのクラスをBeanとして登録したい場合。(そのクラスのソースコードを書き換えて
@Componentを付けることができないため) - Beanの生成ロジックや初期設定を細かく制御したい場合。
今回は、これらの課題を解決する手段である「Java Config」(Javaコードによる設定)について学びます。
1. Java Configの基本:@Configuration と @Bean
Java Configは、その名の通りJavaコードを使ってBeanを定義する方法で、主に @Configuration と @Bean の二つのアノテーションを使用します。
1-1. @Configuration(設定クラス)
@Configuration は、そのクラスが「Beanの定義を行うための設定ファイル」であることをSpringコンテナに伝えるアノテーションです。
このクラス自体も、SpringコンテナによってBeanとして管理されます。
1-2. @Bean(Bean定義メソッド)
@Configuration クラス内のメソッドに @Bean を付けると、そのメソッドが返したオブジェクトがSpringコンテナにBeanとして登録されます。
Java
// Springの設定ファイルとして扱う
@Configuration
public class AppConfig {
// ① @Beanを付けたメソッドが、Beanを生成し、返却する
@Bean
public MySystemConfig systemConfig() {
// newを使ってオブジェクトを生成し、初期設定を行う
MySystemConfig config = new MySystemConfig();
config.setAppName("業務管理システム");
config.setMaxConnections(50);
return config; // この MySystemConfig オブジェクトがBeanとして登録される
}
}
これで、MySystemConfig というBeanがコンテナに登録され、他のServiceクラスなどで @Autowired により注入して使えるようになります。
2. 外部ライブラリのBean登録
Java Configが最も威力を発揮するのは、外部ライブラリのクラスをBeanとして使いたい場合です。
例えば、java.time パッケージの Clock クラス(時刻を扱う標準クラス)を特定の要件で設定して使いたいとします。Clock クラスには @Component を付けられません。
Java
import java.time.Clock;
@Configuration
public class TimeConfig {
@Bean
public Clock fixedClock() {
// システムの現在時刻ではなく、固定時刻を返すClockをBeanとして登録
return Clock.systemUTC();
}
// 他のクラスでこのClock Beanを利用する
}
これで、Clock 型が必要な場所に、常に fixedClock が注入されるようになります。
3. DIの活用:@Bean メソッド間の連携
@Configuration クラスの内部にある @Bean メソッドは、他の @Bean メソッドを呼び出すことができます。この際、Springは呼び出し側のメソッドに、すでにコンテナに登録されているBeanを渡してくれます。
これにより、Bean間の依存関係をJavaコードで明確に記述できます。
Java
// Loggerインターフェースと実装クラスがあると仮定
interface Logger { void log(String msg); }
class ConsoleLogger implements Logger { /* ... 実装省略 ... */ }
@Configuration
public class ServiceConfig {
// ① Logger Bean を定義
@Bean
public Logger consoleLogger() {
return new ConsoleLogger();
}
// ② UserService Bean を定義する際に、Logger Beanに依存させる
// メソッドの引数に Logger Bean を要求するだけで、Springが自動で注入する
@Bean
public UserService userService(Logger consoleLogger) {
// newでUserServiceを生成し、初期設定でLoggerを渡す
return new UserService(consoleLogger);
}
// UserService クラスのコンストラクタは以下のようになっていると想定
// public UserService(Logger logger) { this.logger = logger; }
}
このように、@Bean メソッドの引数として別のBeanを指定することで、コンテナ内の依存関係を構築できます。これは、アノテーションによるDI(@Autowired)と並ぶ、SpringのDIの主要な手段です。
4. アノテーション vs Java Config
どちらの方法を使うべきか迷うかもしれませんが、一般的なルールは以下の通りです。
| 特徴 | アノテーションベース (@Serviceなど) | Java Config (@Configuration + @Bean) |
| 対象 | 自分でソースコードが書けるクラス | 外部ライブラリのクラスや、生成ロジックが複雑なクラス |
| 記述形式 | クラスに印を付けるだけ | Javaコードで生成ロジックを記述 |
| 主流度 | Spring Bootでは最も主流 | 特定のカスタマイズが必要な場合に利用 |
業務開発では、自作クラスはアノテーション、特別な設定や外部ライブラリは Java Config と、両者を併用するのが一般的です。
✅ 本日のまとめ
- Java Configは、Beanの生成ロジックを細かく制御したり、外部ライブラリのクラスをBeanとして登録したりする際に使う。
@Configurationは設定クラスであることを示し、このクラス内でBean定義を行う。@Beanが付いたメソッドは、その戻り値をBeanとしてコンテナに登録する。@Beanメソッドの引数として他のBeanを指定することで、依存関係を構築できる。
🔔 次回予告
これでSpring Coreの核となる知識はほぼ網羅しました。次回は、Beanの定義や設定ファイルにおいて、Javaコードではなく「文字列」として記述できる便利な仕組み、SpEL (Spring Expression Language) について学びます。これは、プロパティファイルの値や、他のBeanのメソッドの結果を参照したい場合に非常に強力な機能です。
次回:【第12回】Spring Expression Language (SpEL) の活用 にご期待ください!


コメント