導入
@Component や @Bean でBeanの「作り方」を教えることは分かりました。では実際にSpringが起動するとき、これらの情報を使って何が起きているのかを俯瞰してみましょう。
説明
DIコンテナの実体は ApplicationContext というオブジェクトです。Springアプリが起動すると、ApplicationContextが次の手順でBeanを組み立てます。
sequenceDiagram
participant Main as main()
participant Ctx as ApplicationContext
Main->>Ctx: 起動する
Ctx->>Ctx: コンポーネントスキャン(@Component等を収集)
Ctx->>Ctx: @Configuration の @Bean 定義も収集
Ctx->>Ctx: 各Beanが必要とする依存関係を解決する
Ctx->>Ctx: 依存の順にインスタンス化し、コンストラクタへ注入する
Ctx-->>Main: 全Beanの組み立てが完了(起動完了)
ここで重要なのは、開発者は「何が必要か」を宣言するだけで、「誰が」「どの順番で」インスタンスを作るかはApplicationContextが解決してくれる、という点です。
ApplicationContext context = SpringApplication.run(MyApp.class, args);
// Beanを直接取り出すこともできる(通常はDIで受け取るので、あまり書かない)
OrderService service = context.getBean(OrderService.class);
普段のアプリ開発では context.getBean(...) を直接呼ぶことはほとんどありません。コンストラクタインジェクションで「必要な依存を宣言する」だけで、裏側のApplicationContextがすべて配線してくれるからです。この「裏側で自動的に組み立てられている」という感覚を持てると、Springのコードが急に読みやすくなります。
やってみよう
OrderService が Notifier を必要とし、Notifier の実装 MailNotifier がさらに何か(例えば MailClient)を必要とする、という3段の依存関係を想像してみましょう。ApplicationContextはこの3つをどの順番で組み立てる必要があるか、図に書き出してみてください。