Spring Bootにおける@Configuration / @Beanって何? 使い方を分かりやすく解説


皆さんはSpring Bootで開発していて、@Configuration@Bean を見かけたことはありますでしょうか?
@Component と何が違うの?」「どこで使うのが正解?」と混乱しがちなポイントでもあります。

この記事では、@Configuration / @Bean の役割と使い方を、具体例を交えて解説します。


@Configurationとは?

@Configuration は「このクラスは設定(Configuration)クラスですよ」とSpringに伝えるアノテーションです。
設定クラスの中で @Bean メソッドを定義し、Springコンテナに登録したいオブジェクト(Bean)を組み立てます。

イメージとしては、「Beanをどう作るかをまとめて書く場所」を用意するのが @Configuration です。


@Beanとは?

@Beanメソッドに付ける アノテーションで、その 戻り値をSpringコンテナにBeanとして登録します。
@Component が「クラスに付けて、クラス自体をBean登録する」のに対し、@Bean は「メソッドが返したオブジェクトをBean登録する」点が大きな違いです。

@Bean が活躍する典型例は以下です。

  • 自分で作っていない(外部ライブラリの)クラスをBean登録したい
  • 生成手順が少し複雑で、newするだけでは終わらない
  • 生成時に設定値や依存Beanを組み合わせたい

基本的な使い方(サンプル)

例えば、外部ライブラリのクラス Clock をBeanとして登録したいとします。クラスに @Component を付けられないので、@Bean の出番です。

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.time.Clock;

@Configuration
public class AppConfig {

    @Bean
    public Clock clock() {
        return Clock.systemDefaultZone();
    }
}

これで Clock がSpringコンテナに登録され、他のクラスからDIできます。

import org.springframework.stereotype.Service;
import java.time.Clock;

@Service
public class TimeService {
    private final Clock clock;

    public TimeService(Clock clock) {
        this.clock = clock;
    }
}

よく使うテクニック

Bean名を指定する

デフォルトでは メソッド名がBean名 になります。
明示したい場合は以下のように指定できます。

@Bean("systemClock")
public Clock clock() {
    return Clock.systemDefaultZone();
}

@Beanメソッドの引数で依存を受け取る(これが便利)

@Bean メソッドは、引数に必要なBeanを書くだけでSpringが解決して渡してくれます。

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AppConfig {

    @Bean
    public MyClient myClient(MyProperties props, Clock clock) {
        return new MyClient(props.getEndpoint(), clock);
    }
}

「Beanを組み立てる場所」として @Configuration を使う旨味が出るポイントです。

スコープを変える(必要なときだけ)

基本はsingleton(アプリ内で1つ)ですが、用途によってはprototypeなどを使うこともあります。

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Scope;

@Bean
@Scope("prototype")
public SomeObject someObject() {
    return new SomeObject();
}

(とはいえ、通常の業務アプリではsingletonがほとんどです)


ハマりやすいポイント

1) @Configurationの「プロキシ」による挙動差

@Configuration が付いたクラスは、内部的にプロキシ化されることで、@Bean メソッド同士の呼び出しが「同一Bean」を返すように調整されます。
そのため、以下のようなコードでも a() が毎回newされる…ではなく、基本的にはコンテナ管理の同一インスタンスが返ります。

@Configuration
public class AppConfig {

    @Bean
    public A a() {
        return new A();
    }

    @Bean
    public B b() {
        return new B(a()); // a() を呼んでいる
    }
}

逆に言うと、@Configuration を付けない(または設定次第)だと、このあたりの挙動が変わって混乱の元になります。
最初のうちは 「@Beanを書くなら素直に@Configurationに寄せる」 と覚えておくと事故が減ります。

2) @Configurationが無くても@Beanは使える?

結論から言うと 使えます。ただし前提があります。

前提:そのクラス自体がSpringの管理下に入っていること

@Bean は「Springが拾ってくれるクラス」の中に書かれて初めて意味を持ちます。
つまり、以下のように クラスそのものがBeanとして登録される状況なら、@Configuration が無くても @Bean は動きます。

  • @Component が付いている
  • @SpringBootApplication 配下でコンポーネントスキャンされる(または @Import される)
  • Java Configとして明示的に読み込まれている

例:@Component でも @Bean は機能します。

import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

import java.time.Clock;

@Component
public class AppConfig {

    @Bean
    public Clock clock() {
        return Clock.systemDefaultZone();
    }
}

この場合も Clock はSpringコンテナにBean登録されます。

ただし、@Configurationがあると安全

@Configuration が付いていると、設定クラスが「フルモード(CGLIBプロキシ)」になり、@Bean メソッド同士の呼び出しがあっても コンテナ管理の同一Bean が返りやすくなります。

逆に @Component などで @Configuration なしの場合、@Bean メソッドを ただのメソッド呼び出しとして扱ってしまい、状況によっては 別インスタンスが生成されることがあります。

そのため、設定クラスとして書くなら 基本は @Configuration を付けるのが無難です。

3) @Componentで済むものを無理に@Beanで書かない

自分のクラスで、生成も単純で、普通にコンポーネントスキャン対象にできるなら @Component / @Service / @Repository などで十分です。
@Bean は「クラスにアノテーションを付けられない」「生成が少し特殊」なときに効きます。


まとめ

  • @Configuration は「Beanの作り方をまとめて書く設定クラス」
  • @Bean は「メソッドの戻り値をSpringコンテナにBean登録する」
  • 外部ライブラリのクラスをDIしたい時や、生成が複雑な時に @Bean が特に便利
  • @Configurationが無くても@Beanは使える(ただし、そのクラスがSpring管理下にあることが前提)
  • ただし、設定クラスとして書くなら @Configurationを付けて運用するのが事故りにくい