導入
Springで開発していると、@Service などのアノテーションを付け忘れてエラーになることがあります。
「エラーが出たら付ける」という対応になりがちですが、なぜ必要なのかはあまり意識されません。
本記事では、@Component系アノテーションが必要な理由を整理します。
@Component系アノテーションをつけない場合の挙動
@Service などを付けていないクラスは、Springの管理対象(Bean)として登録されません。
public class UserService {}
この状態では、Springはこのクラスを「ただのクラス」として扱い、DI(依存性注入)の対象にはなりません。
そのため、以下のように依存注入しようとすると
@Autowired
private UserService userService;
Beanが存在しないため、NoSuchBeanDefinitionException が発生します。
つまり、クラス自体は存在していても、Springからは「管理されていない存在」として扱われている状態です。
Beanとは
Beanとは、Springが管理しているインスタンスのことです。
Springは、Beanとして登録されたクラスに対して
- インスタンスの生成
- 依存関係の解決(DI)
- ライフサイクル管理
などを行います。
そのため、Beanとして登録されていないクラスは、Springの機能(特に依存注入)を利用することができません。
Beanとして登録されていない場合、Springはそのクラスのインスタンスを管理しないため、
@Autowired
private UserService userService;
のような依存注入ができず、エラーになります。
@Component系アノテーションが必要なケースとの違い
すべてのクラスに @Service などが必要なわけではありません。
判断基準はシンプルで、「インスタンスを誰が生成するか」です。
- 自分でインスタンスを生成して使う(自分で
newする) → 不要 - Springにインスタンスの生成を任せる(DIする) → 必要
例えば、以下のように自分で生成するクラスはアノテーション不要です。
new User(...)
一方で、@Autowired などで依存注入したい場合は、Springがインスタンスを管理する必要があるため、@Service などのアノテーションが必要になります。
なぜ@Component系アノテーションを付けないと登録されないのか
Spring Bootでは、起動時にクラスを自動で探し、必要なものをBeanとして登録しています。
このとき使われているのが、@ComponentScan という仕組みです。
@SpringBootApplication には内部的に @ComponentScan が含まれており、指定されたパッケージ配下のクラスがスキャンされます。
ただし、見つかったクラスがすべて登録されるわけではありません。
Springは、以下のようなアノテーションが付いているクラスだけを対象にBeanとして登録します。
@Component@Service@Repository@Controller
これらはまとめて「@Component系アノテーション」と呼ばれます。
つまり、Springは
- クラスを探す(コンポーネントスキャン)
- アノテーションが付いているものだけ登録する
という流れでBeanを管理しています。
つまり、Springはアノテーションを目印にしてBean登録の対象を判断しているため、付いていないクラスは登録されません。
まとめ
@Component系アノテーションは、Springにクラスを管理させるための目印です。
依存注入するクラスにはこれを付けてBeanとして登録しないと、Springの機能を利用することができません。