SpringBoot DI(依存性の注入)のサンプル

Spring BootのDI(依存性の注入)のサンプルです。DIは、Dependency injectionの略です。
(確認環境:Spring Boot 2.5,JDK 11)

目次

サンプル DI(依存性の注入)を行う環境 / DIの概要
  DIの対象になるクラス(SyainNameService.java)
  DIが行われるクラス(MainController.java)
  アプリ起動時にBeanを取得する場合

DI(依存性の注入)を行う環境

画面にアクセスするとコントローラ(MainController.java)でサービスクラス(SyainNameService.java)をDIしメソッドを実行します。

画面に表示する

以下のURLにアクセスすると画面にsuzukiと表示されます。
http://localhost:8080/test1

 

DIの概要

STEP1.SpringがDIする対象のクラスを探してbeanとして管理します。
DIの対象になるクラス(SyainNameService.java)

STEP2.Springが対象の変数にbeanのインスタンスをセットします。
DIが行われるクラス(MainController.java)

 

DIの対象になるクラス(SyainNameService.java)

DIの対象になるクラスです。@Serviceアノテーションを追加します。

package com.example.demo;

import org.springframework.stereotype.Service;

@Service
public class SyainNameService {

	public String getName() {
		return "suzuki";
	}
}

5行目の@Serviceアノテーションがあるクラスは、DIの対象(bean)になりDIコンテナに登録されます。DIの対象になるアノテーションは他にもあります。

以下はDIの対象になるアノテーションでよく使用されるものです。

アノテーション 説明
@Service サービスクラスにつけます
@Component DIコンテナに登録する場合につけます
@Controller コントローラークラスにつけます
@Repository DAO(DB)のクラスにつけます

 

DIが行われるクラス(MainController.java)

DIが行われるクラスです。

package com.example.demo;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class MainController {
	
	private final SyainNameService syainNameService; 
	
//	@Autowired
//	SyainNameService syainNameService ;
	public MainController(SyainNameService syainNameService) {
		this.syainNameService = syainNameService;
	}
	
	@GetMapping("/test1")
	public String write1() {
		return syainNameService.getName();
	}
}

9,13,14行目は、SpringがDIコンテナからSyainNameServiceクラスをnewしてインスタンスを変数syainNameServiceに設定します。これがDI(依存性の注入)です。
コンストラクタを使用するのでコンストラクタインジェクションと呼ばれます。

11,12行目のAutowiredアノテーションと変数でもDIできます。フィールドインジェクションと呼ばれます。使用する場合はコンストラクタインジェクションが推奨されています。

依存とは

MainControllerクラスは、SyainNameServiceクラスのインスタンスを必要としている。→依存

注入とは

Spring Frameworkが、SyainNameServiceクラスをインスタンス化してセットする。→注入

結果として制御の反転(Inversion of Control、IoC)になる

依存関係が逆になります。
newを使用した場合:MainControllerクラスがSyainNameServiceクラスをnewして使う。
DIの場合:MainControllerクラスは、何らかのインスタンスを渡されて使う。

DIの利点

・疎結合となり実装の切り替えがやりやすくなります。
bean側にProfileアノテーションをつける場合、開発時と本番時で使用するクラスを変える等の設定ができます。使用するインスタンスはSpringが注入してくれるので呼び出し元(ここではMainControllerクラス)のコードの変更は不要です。単体テストもモック等の使用が容易になります。

・ScopeアノテーションでBeanのインスタンスのスコープも容易に選択できます。
デフォルトはシングルトン(singleton)です。開始から終了までインスタンスは1つのみ生成されます。都度インスタンス化する場合はプロトタイプ(prototype)を指定します。

以下は、springのAutowiredアノテーションのリンクです。
https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/beans/factory/annotation/Autowired.html

 

アプリ起動時にBeanを取得する場合

1.@Configurationと@Beanを追加する(AppConfig.java)

以下のファイルを追加します。

package com.example.demo;

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

@Configuration
public class AppConfig {
	@Bean
	public SyainNameService syainName() {
		return new SyainNameService();
	}
}

6行目の@Configurationは、beanの設定を行うことを表します。
8行目に@Beanがあります。
10行目の戻り値であるクラスのインスタンスはbeanになります。

Configurationとは構成という意味です。

 

2.起動ファイルを修正(SbApplication.java)

DIコンテナからbeanを取得して実行します。

package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

@SpringBootApplication
public class SbApplication {

	public static void main(String[] args) {

		SpringApplication.run(SbApplication.class, args);

		ApplicationContext context 
			= new AnnotationConfigApplicationContext(AppConfig.class);
		SyainNameService service 
			= context.getBean(SyainNameService.class);
		System.out.println(service.getName()); // suzuki
	}
}

16行目のAppconfig.classは、@Configurationがあるクラスです。
18行目は、getBeanでbeanを取得しています。
19行目は、メソッドを実行して文字列を出力しています。

以下は、springのConfigurationアノテーションのリンクです。

https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/annotation/Configuration.html

pom.xml

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

関連の記事

SpringBoot コンストラクタインジェクション
SpringBoot AOPのサンプル

△上に戻る