Spring Boot
Spring Frameworkベースの本番対応Javaアプリケーションを簡単に作成できるフレームワーク。最小限の設定でSpringアプリケーション作成。組み込みWebサーバー対応。
アプリケーションサーバー
Spring Boot
概要
Spring Bootは、Spring Frameworkをベースとした本番対応Javaアプリケーションを最小限の設定で作成できるフレームワークです。「設定より規約」(Convention over Configuration)の原則に基づき、複雑なSpringアプリケーションの設定を大幅に簡素化します。組み込みWebサーバー(Tomcat、Jetty、Undertow)を標準サポートし、スタンドアロンJARファイルとして実行可能なアプリケーションを作成できます。
詳細
Spring Bootは2014年にリリースされ、Enterprise Java開発で最も人気の高いフレームワークとなっています。現在のバージョン3.xでは、GraalVMネイティブイメージ、Virtual Threads(Project Loom)、Jakarta EE移行など、現代的な開発に最適化された機能を提供しています。
主要な技術的特徴
- 自動設定(Auto Configuration): 依存関係に基づく自動的な設定機能
- 組み込みWebサーバー: Tomcat、Jetty、Undertowの組み込みサポート
- Production Ready機能: Actuatorによる監視・ヘルスチェック機能
- 外部設定: application.yml/propertiesによる設定外部化
- DevToolsサポート: 開発時の自動リロード機能
用途
- エンタープライズWebアプリケーション
- RESTful APIサーバー
- マイクロサービスアーキテクチャ
- バッチアプリケーション
- クラウドネイティブアプリケーション
メリット・デメリット
メリット
- 簡単な設定: ボイラープレートコードの大幅削減
- 高い生産性: 迅速なアプリケーション開発が可能
- 豊富なエコシステム: Spring生態系との完全統合
- Production Ready: 運用に必要な機能が標準装備
- 強力なコミュニティ: 大規模なコミュニティとサポート
- エンタープライズ対応: 大規模システムでの実績
デメリット
- 学習曲線: Spring Framework全体の理解が必要
- メモリ使用量: 比較的高いメモリ消費
- 起動時間: 大規模アプリケーションでの起動時間
- 依存関係の複雑さ: 自動設定による依存関係の見通しの悪さ
- バージョン互換性: メジャーバージョン間での破壊的変更
参考ページ
書き方の例
基本的なアプリケーション設定
package com.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@SpringBootApplication
@RestController
public class Application {
@GetMapping("/")
public String home() {
return "Hello Spring Boot!";
}
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
application.yml設定例
server:
port: 8080
servlet:
context-path: /api
spring:
datasource:
url: jdbc:mysql://localhost:3306/mydb
username: user
password: password
driver-class-name: com.mysql.cj.jdbc.Driver
jpa:
hibernate:
ddl-auto: update
show-sql: true
properties:
hibernate:
format_sql: true
profiles:
active: development
logging:
level:
com.example: DEBUG
org.springframework.web: INFO
pattern:
console: "%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n"
management:
endpoints:
web:
exposure:
include: health,info,metrics,prometheus
endpoint:
health:
show-details: always
RESTful APIコントローラー
package com.example.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import com.example.service.UserService;
import com.example.entity.User;
@RestController
@RequestMapping("/api/users")
@CrossOrigin(origins = "*")
public class UserController {
@Autowired
private UserService userService;
@GetMapping
public ResponseEntity<List<User>> getAllUsers() {
List<User> users = userService.findAll();
return ResponseEntity.ok(users);
}
@GetMapping("/{id}")
public ResponseEntity<User> getUserById(@PathVariable Long id) {
User user = userService.findById(id);
return user != null ? ResponseEntity.ok(user) : ResponseEntity.notFound().build();
}
@PostMapping
public ResponseEntity<User> createUser(@RequestBody @Valid User user) {
User savedUser = userService.save(user);
return ResponseEntity.status(HttpStatus.CREATED).body(savedUser);
}
@PutMapping("/{id}")
public ResponseEntity<User> updateUser(@PathVariable Long id, @RequestBody @Valid User user) {
User updatedUser = userService.update(id, user);
return ResponseEntity.ok(updatedUser);
}
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteUser(@PathVariable Long id) {
userService.deleteById(id);
return ResponseEntity.noContent().build();
}
}
JPA Entity設定
package com.example.entity;
import jakarta.persistence.*;
import jakarta.validation.constraints.*;
import java.time.LocalDateTime;
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, unique = true)
@NotBlank(message = "Username is required")
@Size(min = 3, max = 50)
private String username;
@Column(nullable = false, unique = true)
@Email(message = "Valid email is required")
private String email;
@Column(nullable = false)
@NotBlank(message = "Password is required")
@Size(min = 8)
private String password;
@CreationTimestamp
@Column(name = "created_at", updatable = false)
private LocalDateTime createdAt;
@UpdateTimestamp
@Column(name = "updated_at")
private LocalDateTime updatedAt;
// Constructors, Getters, Setters
public User() {}
public User(String username, String email, String password) {
this.username = username;
this.email = email;
this.password = password;
}
// Getters and Setters...
}
Service Layer実装
package com.example.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.example.repository.UserRepository;
import com.example.entity.User;
@Service
@Transactional
public class UserService {
@Autowired
private UserRepository userRepository;
@Autowired
private PasswordEncoder passwordEncoder;
public List<User> findAll() {
return userRepository.findAll();
}
public User findById(Long id) {
return userRepository.findById(id).orElse(null);
}
public User findByUsername(String username) {
return userRepository.findByUsername(username);
}
public User save(User user) {
user.setPassword(passwordEncoder.encode(user.getPassword()));
return userRepository.save(user);
}
public User update(Long id, User userDetails) {
User user = findById(id);
if (user != null) {
user.setUsername(userDetails.getUsername());
user.setEmail(userDetails.getEmail());
if (userDetails.getPassword() != null) {
user.setPassword(passwordEncoder.encode(userDetails.getPassword()));
}
return userRepository.save(user);
}
return null;
}
public void deleteById(Long id) {
userRepository.deleteById(id);
}
}
Spring Security設定
package com.example.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.csrf(csrf -> csrf.disable())
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authorizeHttpRequests(authz -> authz
.requestMatchers("/api/auth/**").permitAll()
.requestMatchers("/api/public/**").permitAll()
.requestMatchers("/actuator/**").permitAll()
.anyRequest().authenticated()
)
.oauth2ResourceServer(oauth2 -> oauth2.jwt());
return http.build();
}
}
Maven pom.xml設定
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.3.0</version>
<relativePath/>
</parent>
<groupId>com.example</groupId>
<artifactId>spring-boot-app</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<!-- Web Starter -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Data JPA -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- Security -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- Validation -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<!-- Actuator -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- MySQL -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!-- Test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>