【Spring Boot】素のSpring Bootでできること
なにも追加しない Spring Boot プロジェクトでも使える基本的な機能をまとめました。
1. 動作環境
- macOS 14.5
- Java 21
- Gradle 8.8
- Spring Boot 3.3.1
2. DI コンテナの利用
Spring Boot は Bean と呼ばれるオブジェクトを管理し、それらの Bean 間の依存関係を注入して任意の場所で参照できます。
2.1. Bean の定義方法
Bean の定義には以下の方法があります[1]。Bean は一意の名前で管理されます。
- アノテーションベースの設定
- Java ベースの設定
- XML ベースの設定
2.1.1. アノテーションベースの設定
@Component
、@Service
、@Repository
、@Controller
などのアノテーションをクラスに付与すると、そのインスタンスが Bean として管理されます。
Bean 名はクラス名の先頭を小文字にしたものになります。
package com.example.demo;
import org.springframework.stereotype.Component;
@Component
public class DemoComponent {
public void helloworld() {
System.out.println("Hello, world!");
}
}
2.1.2. Java ベースの設定
@Configuration
アノテーションを付与したクラス内で @Bean
アノテーションを付与したメソッドを定義すると、そのメソッドの戻り値が Bean として管理されます。
Bean 名はメソッド名になります。
package com.example.demo;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class DemoConfig {
@Bean
DemoConfBean demoConfBean() {
return new DemoConfBean();
}
}
2.1.3. XML ベースの設定
XML ファイル内で Bean とその依存関係を定義し、@ImportResource
アノテーションでインポートします。
Bean 名は<bean>
タグの id
になります。
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="demoXml" class="com.example.demo.DemoXml"/>
</beans>
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ImportResource;
@SpringBootApplication
@ImportResource("classpath:beans.xml")
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
2.2. Bean の参照方法
Bean の参照には以下の方法があります。
- コンストラクタインジェクション
- セッターインジェクション
- フィールドインジェクション
-
@Bean
アノテーションを使ったインジェクション -
ApplicationContext
を使用した Bean の取得
2.2.1. コンストラクタインジェクション
@Autowired
アノテーションを付与したコンストラクタを使用してインジェクションします。
package com.example.demo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class DemoComponent {
private final DemoService demoService;
@Autowired
public DemoComponent(DemoService demoService) {
this.demoService = demoService;
}
public void exec() {
demoService.service();
}
}
2.2.2. セッターインジェクション
@Autowired
アノテーションを付与したセッターメソッドを使用してインジェクションします。
package com.example.demo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class DemoComponent {
private DemoService demoService;
@Autowired
void setDemoService(DemoService demoService) {
this.demoService = demoService;
}
public void exec() {
demoService.service();
}
}
2.2.3. フィールドインジェクション
フィールドに @Autowired
アノテーションを付与してインジェクションします。
package com.example.demo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class DemoComponent {
@Autowired
private DemoService demoService;
public void exec() {
demoService.service();
}
}
2.2.4. @Bean アノテーションを使ったインジェクション
@Bean
アノテーションを付与したメソッドの引数にインジェクションします。
package com.example.demo;
import org.springframework.boot.ApplicationRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class DemoConfig {
@Bean
ApplicationRunner exec(DemoService demoService) {
return args -> {
demoService.service();
};
}
}
2.2.5. ApplicationContext を使用した Bean の取得
ApplicationContext
の getBean
メソッドで取得します。
package com.example.demo;
import org.springframework.boot.ApplicationRunner;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class DemoConfig {
@Bean
ApplicationRunner exec(ApplicationContext applicationContext) {
return args -> {
DemoService demoService = applicationContext.getBean(DemoService.class);
demoService.service();
};
}
}
3. 自動実行 Bean の利用
CommandLineRunner
または ApplicationRunner
インターフェースを実装した Bean はアプリケーション起動時に自動実行されます。例えば以下のクラスを追加して実行すると Hello, world!
が表示されます。CommandLineRunner
と ApplicationRunner
は run
メソッドの引数に違いがあります。
package com.example.demo;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
@Component
public class DemoRunner implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
System.out.println("Hello, world!");
}
}
4. コマンドライン引数の参照
コマンドライン引数を参照するには ApplicationArguments
を参照します。ApplicationArguments
は Spring Boot によって自動的に Bean として登録されています。
package com.example.demo;
import org.springframework.boot.ApplicationArguments;
import org.springframework.stereotype.Component;
@Component
public class DemoComponent {
private final ApplicationArguments applicationArguments;
@Autowired
public DemoComponent(ApplicationArguments applicationArguments) {
this.applicationArguments = applicationArguments;
}
public void exec() {
System.out.println(applicationArguments.getOptionNames());
}
}
5. 終了コードの設定
終了コードを返す必要がある場合には、まず ExitCodeGenerator
を実装した Bean を定義し getExitCode
メソッドをオーバーライドします。
package com.example.demo;
import org.springframework.boot.ExitCodeGenerator;
import org.springframework.stereotype.Component;
@Component
public class DemoExitCodeGenerator implements ExitCodeGenerator {
private int exitCode = 0;
public void setExitCode(int exitCode) {
this.exitCode = exitCode;
}
@Override
public int getExitCode() {
return exitCode;
}
}
次に以下のように main
メソッドの SpringApplication.run
の戻り値を SpringApplication.exit
に渡し System.exit
を呼び出します。
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
System.exit(SpringApplication.exit(SpringApplication.run(DemoApplication.class, args)));
}
}
そして終了コードを設定する箇所では ExitCodeGenerator
の実装の Bean を参照して終了コードを設定します。
package com.example.demo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class DemoComponent {
private final DemoExitCodeGenerator demoExitCodeGenerator;
@Autowired
public DemoComponent(DemoExitCodeGenerator demoExitCodeGenerator) {
this.demoExitCodeGenerator = demoExitCodeGenerator;
}
public void exec() {
/*
* 何らかの処理
*/
demoExitCodeGenerator.setExitCode(1); // 終了コードの設定
}
}
6. プロパティの参照
Spring Boot アプリケーションのパラメータを定義する application.properties
や application.yml
には独自のカスタム設定値も自由に定義できます。
これらを参照するには以下の様な方法があります。
-
@Value
アノテーションを使用する -
@ConfigurationProperties
アノテーションを使用する -
Environment
オブジェクトを使用する
@Value
アノテーションを使用する
6.1. フィールドにプロパティ名を指定した @Value
アノテーションを付与します。
package com.example.demo;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class DemoComponent {
@Value("${demo.name}")
private String name;
@Value("${demo.version}")
private String version;
@Value("${demo.description}")
private String description;
public void exec() {
System.out.println(name);
System.out.println(version);
System.out.println(description);
}
}
6.2. @ConfigurationProperties アノテーションを使用する
@Configuration
アノテーション及び、プロパティ名のプレフィックスを指定した@ConfigurationProperties
アノテーションを付与したクラスを作成します。
package com.example.demo;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
@Configuration
@ConfigurationProperties(prefix = "demo")
public class DemoProperties {
private String name;
private String version;
private String description;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}
6.3. Environment オブジェクトを使用する
Environment
オブジェクトの getProperty
メソッドにプロパティ名を指定します。
package com.example.demo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
@Component
public class DemoComponent {
private final Environment environment;
@Autowired
public DemoComponent(Environment environment) {
this.environment = environment;
}
public void exec() {
System.out.println(environment.getProperty("demo.name"));
System.out.println(environment.getProperty("demo.version"));
System.out.println(environment.getProperty("demo.description"));
}
}
7. ログの出力
ログライブラリが含まれているので以下の様にLogger
を宣言してそのままログの出力を行えます。
package com.example.demo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
@Component
public class DemoComponent {
private final Logger logger = LoggerFactory.getLogger(DemoComponent.class);
public void exec() {
logger.info("info!");
}
}
デフォルトではコンソールのみにログが出力されます。プロパティにはログレベルを指定するlogging.level.*
やログファイル名を指定するlogging.file.name
などがあり簡単に設定できます。より詳細な設定をしたい場合は logback-spring.xml
[2]または logback.xml
などを作成し、src/main/resources
ディレクトリに配備するかlogging.config
プロパティに指定します。
Spring Boot では以下のライブラリをサポートしています。
- SLF4J
- Logback
- Log4j2
- JUL
- Commons Logging
8. ユニットテスト
JUnit 5、AssertJ、Mockito などのライブラリが含まれています。@SpringBootTest
アノテーションをテストクラスに付与することで Bean をテストクラスにインジェクションしてテストすることができます。
package com.example.demo;
import static org.assertj.core.api.Assertions.assertThat;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class DemoCalculatorTests {
@Autowired
private DemoCalculator demoCalculator;
@Test
void testAdd() {
// 加算のテスト
assertThat(demoCalculator.add(10, 20)).isEqualTo(30);
}
}
@MockBean
アノテーションを使用することで テスト対象コンポーネントが依存している Bean を簡単にモックに置き換えることができます。
package com.example.demo;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.when;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
@SpringBootTest
class DemoComponentTests {
@Autowired
private DemoComponent demoComponent;
@MockBean
private DemoDice demoDice; // DemoComponentが依存しているBeanのモック
@Test
void testExec1() {
// モック(demoDice)のroll()呼び出しの戻り値を2にする
when(demoDice.roll()).thenReturn(2);
assertThat(demoComponent.exec()).isEqualTo("偶数");
}
@Test
void testExec2() {
// モック(demoDice)のroll()呼び出しの戻り値を1にする
when(demoDice.roll()).thenReturn(1);
assertThat(demoComponent.exec()).isEqualTo("奇数");
}
}
Discussion