Spring FrameworkはDIコンテナというJavaのインスタンスを格納する箱を持っている。
Spring Frameworkにおいては、アプリケーション実行時にインスタンスを生成してDIコンテナに保持する。
- DIコンテナ:Spring Frameworkの動作に必要なインスタンスを保持する入れ物
- あるBeanを別のBeanに代入する(Dependency Injection)
- トランザクション管理などの割り込み処理を織り込む(Aspected Oriented Programming)
- Beanインスタンスのライフサイクルを管理する
- Bean:DIコンテナで管理されているインスタンス
- Bean定義の方法
- コンポーネントスキャンによる定義
- Java Configクラスによる定義
- Bean定義の方法
本章では、「コンポーネントスキャン」、「Java Config」を使ってBeanの定義を行い、DIコンテナから取り出す一連の流れを学ぶ。
結局DIってなんなの?
- DIとは「依存性の注入」
- 依存性:必要なインスタンス
- 注入:自動的代入 つまり、DIとは 「newしないで代入してもらう」 こと
- コンポーネントスキャン:指定されたパッケージから「@Component」が付与されたクラスを探す
- 「@Component」が付与されたクラスがあればインスタンス化しDIコンテナに格納する
DIコンテナ・Beanに必要な設定クラスを作成する。この設定クラスをJava Configという。
- AppConfig.java
package com.example.springdicontainer.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan(basePackages = {"com.example.springdicontainer.data"})
public class AppConfig {
}
アノテーション | 説明 |
---|---|
@Configuration | Java Configであることを示す |
@ComponentScan | Java Configに付与。basePackages属性のパッケージ配下から@Componentが付与されたクラスを探してインスタンス化しDIコンテナに保持 |
※@Component が付与されていても、コンポーネントスキャンの対象ではない場合、Beanにはならない。
Java Configファイル内にてコンポネントスキャンの対象に
@ComponentScan(basePackages = {"com.example.springdicontainer.data"})
と指定されているため「com.example.springdicontainer.data」を作成し、パッケージ配下にBeanにしたいクラスを作成する。
- Logic.java:「src/main/java/com/example/springdicontainer/data/Logic.java」
- 「@Component」アノテーションを付与することでコンポーネントスキャンの対象となる
package com.example.springdicontainer.data;
import org.springframework.stereotype.Component;
@Component
public class Logic {
public void logicMethod() {
System.out.println("logicMethodを実行します");
}
}
DIコンテナは「SpringApplication.run()」メソッドで作成される。
Java Configクラスを引数に与え、戻り値である「ApplicationContext」がDIコンテナとなる。
DIコンテナの作成は
// DIコンテナの作成
ApplicationContext context = SpringApplication.run(AppConfig.class, args);
の一文で実行され、次の処理が行われる。
- Java Configクラスの読み込み
- コンポーネントスキャン
- Beanインスタンスの生成とBeanインスタンスをDIコンテナ内に保存
これを実行後、AppConfig.classの「@ComponentScan」内にある「com/example/data/Logic.java」クラスのインスタンスがDIコンテナ内にある状態となる。
Beanの取り出しには「ApplicationContextのgetBean()」メソッドを使用する。
- SpringDiContainerApplication:「src/main/java/com/example/springdicontainer」
アノテーション | 説明 |
---|---|
@SpringBootApplication | @Configuration・@ComponentScan・@EnableAutoConfigurationを組み合わせたアノテーション @ComponentScanでパッケージが指定されていないため、このクラスのパッケージがベースパッケージとなる |
package com.example.springdicontainer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import com.example.springdicontainer.config.AppConfig;
import com.example.springdicontainer.data.Logic;
@SpringBootApplication
public class SpringDiContainerApplication {
public static void main(String[] args) {
// DIコンテナの作成
ApplicationContext context = SpringApplication.run(AppConfig.class, args);
// Beanの呼び出し
Logic logic = context.getBean(Logic.class);
logic.logicMethod();
}
}
「SpringDiContainerApplication」を右クリックし、「Java アプリケーション」として実行する。すると以下のように、DIコンテナからBeanの取り出しができていることがわかる。
2023-01-05T15:26:52.026+09:00 INFO 49854 --- [ main] c.e.s.SpringDiContainerApplication : Starting SpringDiContainerApplication using Java 17.0.5 with PID 49854 (/home/is0383kk/workspace/workspace_sp/spring-di-container/bin/main started by is0383kk in /home/is0383kk/workspace/workspace_sp/spring-di-container)
2023-01-05T15:26:52.029+09:00 INFO 49854 --- [ main] c.e.s.SpringDiContainerApplication : No active profile set, falling back to 1 default profile: "default"
2023-01-05T15:26:52.164+09:00 INFO 49854 --- [ main] c.e.s.SpringDiContainerApplication : Started SpringDiContainerApplication in 0.367 seconds (process running for 0.634)
logicMethodを実行します
1つ目のアノテーションによる定義は便利である一方で、ライブラリ内のクラスなどは「@Component」アノテーションを付与できない場合がある。
そこで、本章ではJava Configクラスにメソッドを作成しBeanを定義する方法を学ぶ。
今回は、あえてBeanとしてクラスに「@Component」アノテーションを付与しない
- Logic.java:「src/main/java/com/example/springdicontainer2/data/Logic.java」
- 「@Component」アノテーションを付与しないため、このままではコンポーネントスキャンの対象外
package com.example.springdicontainer2.data;
// @Componentは付与しない
public class Logic {
public void logicMethod() {
System.out.println("logicMethodを実行します");
}
}
Java Configを作成する。
今回はコンポーネントスキャンを行わないため、「@ComponentScan」アノテーションは付与しない。
- AppConfig.java:「com.example.springdicontainer2.config.AppConfig.java」
- Java Configクラス内で「@Bean」アノテーションを付与することで戻り値のインスタンスがBeanとなりDIコンテナに格納される
package com.example.springdicontainer2.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.example.springdicontainer2.data.Logic;
@Configuration
public class AppConfig {
@Bean
Logic logicMethod() {
return new Logic();
}
}
Beanの取り出しには「ApplicationContextのgetBean()」メソッドを使用する。
- SpringDiContainerApplication:「src/main/java/com/example/springdicontainer」
package com.example.springdicontainer2;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import com.example.springdicontainer2.config.AppConfig;
import com.example.springdicontainer2.data.Logic;
@SpringBootApplication
public class SpringDiContainer2Application {
public static void main(String[] args) {
// DIコンテナの作成
ApplicationContext context = SpringApplication.run(AppConfig.class, args);
// Beanの呼び出し
Logic logic = context.getBean(Logic.class);
logic.logicMethod();
}
}
「SpringDiContainerApplication」を右クリックし、「Java アプリケーション」として実行する。すると以下のように、DIコンテナからBeanの取り出しができていることがわかる。
2023-01-05T15:54:37.177+09:00 INFO 51688 --- [ main] c.e.s.SpringDiContainer2Application : Starting SpringDiContainer2Application using Java 17.0.5 with PID 51688 (/home/is0383kk/workspace/workspace_sp/spring-di-container-2/bin/main started by is0383kk in /home/is0383kk/workspace/workspace_sp/spring-di-container-2)
2023-01-05T15:54:37.180+09:00 INFO 51688 --- [ main] c.e.s.SpringDiContainer2Application : No active profile set, falling back to 1 default profile: "default"
2023-01-05T15:54:37.301+09:00 INFO 51688 --- [ main] c.e.s.SpringDiContainer2Application : Started SpringDiContainer2Application in 0.33 seconds (process running for 0.579)
logicMethodを実行します