Re:ゼロから始めるSpring Boot #6 Beanの管理
Beanとは
Beanとは、アプリケーション全体で管理されるオブジェクトのこと。Beanによって、依存性管理やオブジェクトのライフサイクル管理が効率的に行われる。
なぜBeanが重要かというと、Spring Bootではアプリケーションが大規模になっても、オブジェクトの生成や依存関係の管理を自動化することで、開発者の負担を大幅に減らせるからです。Beanは、DI(依存性注入)の仕組みの中心にあり、アプリケーション全体で必要なオブジェクトを適切に共有・管理する役割を担っています。
例えば、@Serviceアノテーションを付けたクラスは、自動的にBeanとして登録されます。次に、コントローラークラスで@Autowiredを使えば、そのサービスクラスのインスタンスを自動的に注入して使うことができます。これにより、わざわざnewしてインスタンスを作る必要がなくなり、コードの保守性が向上します。
つまり、Spring BootにおけるBeanとは、アプリケーションの構成要素を管理するための仕組みであり、開発効率とアプリケーションの品質を高めるために欠かせない存在です。
Beanの管理
Springでは Beanの管理は主に2つのプロセスがある。Spring Bootでは、Beanの管理はほとんど自動化されているため意識する必要はないが、AutoConfigurationを理解するのに必要な知識である。
Beanのスキャン
Springでは、Beanをスキャンする方法は2つあります。
- XMLファイルに
component-scan
タグを記載する方法<context:component-scan base-package="com.RezeroSB"/>
- @ComponentScan アノテーションを付ける方法
@ComponentScan(base-package="com.RezeroSB")
spring Bootでは、意図的にいずれも行っていない、行う必要がない。下記リンク先が例。
なぜなら、スタータークラスについている@SpringBootApplication
に含まれているからである。
しかし、@ComponentScanはスキャンされるパッケージの階層は指定されていない。デフォルトではスタータークラスが存在するパッケージ内でスキャンが行われる。パッケージを指定したい場合は、以下の楊に別途記述が必要。
@SpringBootApplication
@ComponentScan(basePackages = "com.rezerosb") //←これ
public class RezeroSb05MybatisApplication {
public static void main(String[] args) {
SpringApplication.run(RezeroSb05MybatisApplication.class, args);
}
}
Beanの登録
Springでは、下記4つのアノテーションを使ってBeanを定義するのが一般的である。
アノテーション | 説明 | 適用場所 |
---|---|---|
@Component | Beanを定義する基本的なアノテーション | 下記の3つに該当しない場合に使用 |
@Controller | @Componentの派生アノテーション | コントローラークラスに付ける |
@Service | @Componentの派生アノテーション | ビジネスロジックを持つクラスに付ける |
@Repository | @Componentの派生アノテーション | データアクセスクラスに付ける(MyBatisと連携するため使用頻度は少なめ) |
しかし、登録したいBeanオブジェクトが自作ではない場合は、@Componentやその派生アノテーションではBeanを宣言することはできない。この場合は、@Bean
と@Import
アノテーションを使ってBeanオブジェクトを登録することができる。
Hands-onの準備
1.適当に外部(サードパーティ)のjarパッケージをMavenリポジトリにインストールする。
ソースコードはこちら:https://github.com/Willyangl/ReZeroSpringBoot/tree/497bae769ddd9523500894e4dcca5f41356bff0e/BeanRegisterMaterial
2.Spring Bootのプロジェクトを作成し、1でインストールしたパッケージをpom.xmlにdependencyとして追加する。
@BeanでBeanを登録
@SpringBootApplication
public class ReZeroSb06BeanRegisterApplication {
public static void main(String[] args) {
//登録したBeanを確認するためのコード
ApplicationContext context = SpringApplication.run(ReZeroSb06BeanRegisterApplication.class, args);
Country country = context.getBean(Country.class);
System.out.println(country);
//getBeanはメソッド名を利用できる
System.out.println(context.getBean("province"));
}
//CountryオブジェをBeanとして登録
@Bean //メソッドの戻り値をIOCコンテナに管理させ、IOCコンテナのBeanオブジェクトとする
public Country country(){
return new Country();
}
}
実行結果
2025-04-26T12:25:27.201+09:00 INFO 7604 --- [ReZeroSB06-BeanRegister] [ restartedMain] c.r.r.ReZeroSb06BeanRegisterApplication : Started ReZeroSb06BeanRegisterApplication in 0.378 seconds (process running for 0.626)
Country{name='null', system='null'}
Province{name='null', direction='null'}
Process finished with exit code 0
CountryとProvinceオブジェクトは問題なく取り出せたね。nullになっているのは、newしたとき値を設定しなかったのが原因なので問題なし。
しかし、コードの可読性やメンテナビリティを考慮し、スタータークラスでBeanを登録するのは不適切であるため、おすすめではない。一般的には、@Configuration クラスで登録することがおすすめ。
@Configuration クラスでBeanを登録
やり方:
スタータークラスが存在するパッケージ内でconfig``パッケージを作成し、その中に
CommonConfigクラスを作成する。
CommonConfig```クラス内でBeanを登録する。
@Configuration
public class CommonConfig {
//CountryオブジェをBeanとして登録
@Bean //メソッドの戻り値をIOCコンテナに管理させ、IOCコンテナのBeanオブジェクトとする
public Country country(){
return new Country();
}
}
これでスタータークラスはすっきりして気持ちいいね。
@ImportでBeanを登録
インポートしたいクラスは少ない場合は、@Import
を使ってインポートすればよい。
インポートしたいクラスは複数ある場合は、設定ファイルで一括インポートするといい。
インポートしたいクラスは少ない場合、@Configurationクラスをインポートする方法
スタータークラスの上に@Import(XXX.class)
アノテーションを付けることでBeanのインポートができる。補足:インポートのクラスは、スタータークラスと異なるパッケージに配置してもOK。
//@Import(XXX.class)
@SpringBootApplication
@Import(CommonConfig.class) //← 先ほどと同じCommonConfigクラスを使っている。
public class SpringbootRegistApplication {
略
}
@Configurationクラスが複数ある場合は
//@Import(XXX.class)
@SpringBootApplication
@Import({CommonConfig.class,AAA.class,BBB.class}) //← @Configurationクラスを一々書く必要があるのでエレガントじゃないね。
public class SpringbootRegistApplication {
略
}
インポートしたいクラスは複数ある場合、設定ファイルで一括インポートする方法
1.設定ファイルに@Configurationクラスの一括管理する。
2.ImportSelectorインターフェースの実装クラスを使って一括インポートする。
具体的なやり方は以下。
(1).resorceディレクトリー下に、commmon.imports
ファイルを作成し、インポートしたいクラスのリファレンスを記載する。
(2).ImportSelectorインターフェースの実装クラスを作成
public class CommonImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
//設定ファイルの内容を読み取る
List<String> imports = new ArrayList<>();
InputStream is = CommonImportSelector.class.getClassLoader().getResourceAsStream("common.imports");
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String line = null;
try {
while((line = br.readLine())!=null){
imports.add(line);
}
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
if (br!=null){
try {
br.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
return imports.toArray(new String[0]);
}
}
(3).スタータークラスの上にアノテーションを付ける。
@SpringBootApplication
@Import(CommonImportSelector.class) //←これ
public class ReZeroSb06BeanRegisterApplication {
public static void main(String[] args) {
//略
}
}
実行結果:
Country{name='null', system='null'}
Province{name='null', direction='null'}
Process finished with exit code 0
ソースコード:https://github.com/Willyangl/ReZeroSpringBoot/tree/master/ReZeroSB06-BeanRegister
Discussion