Appearance
Spring Boot 2.x 版本指南
官方介绍
Spring Boot 2.x 是 Pivotal Software(现 VMware Tanzu)推出的 Spring Boot 框架的重要版本系列,基于 Spring Framework 5.x 构建。2.x 版本引入了众多现代化特性和改进,包括对 Java 8+ 的最低要求、响应式编程支持、性能优化以及对云原生应用的更好支持。这个版本标志着 Spring 生态系统向现代化微服务架构的重要转变。
Spring Boot 2.x 旨在简化 Spring 应用的初始搭建以及开发过程,通过约定优于配置的理念,让开发者能够快速创建独立的、生产级别的基于 Spring 框架的应用程序。
版本特性
核心特性
- Java 8+ 最低要求: 强制要求 Java 8 或更高版本
- 响应式编程支持: 内置 Project Reactor,支持响应式编程模型
- Spring Framework 5.x 基础: 基于 Spring Framework 5.x,提供现代化特性
- 嵌入式服务器升级: 默认使用 Tomcat 8.5+, Jetty 9.4+, Undertow 1.4+
- 指标监控: 内置 Micrometer 指标收集,替代了旧的 Metrics
- 安全性: 增强的安全配置和默认安全策略
2.x 版本演进
- 2.0.x: 初始版本,全面升级到 Spring Framework 5,引入响应式编程
- 2.1.x: 增强了对 Kotlin 的支持,改进了性能和监控
- 2.2.x: 增强了对 Java 13 的支持,改进了自动配置
- 2.3.x: 增强了容器化支持,改进了启动时间和内存占用
- 2.4.x: 改进了配置加载机制,增强了对云原生的支持
- 2.5.x: 最终维护版本,持续的安全和 bug 修复
官方获取地址
bash
# 通过 Maven 创建 Spring Boot 2.x 项目
mvn archetype:generate -DgroupId=com.example \
-DartifactId=spring-boot-2-app \
-DarchetypeArtifactId=maven-archetype-quickstart \
-DinteractiveMode=false
# 或者使用 Spring Boot CLI
spring init --dependencies=web,data-jpa --boot-version=2.7.14 spring-boot-2-project或者通过 Spring Initializr 网站:
- 访问 https://start.spring.io
- 选择 Spring Boot 2.x 版本
环境要求
- Java: JDK 8 或更高版本(JDK 11+ 推荐)
- Maven: 3.5+ 或 Gradle 4.10+
- 构建工具: Maven 或 Gradle
- 操作系统: 跨平台支持(Linux、Windows、macOS)
- 嵌入式服务器: Tomcat 8.5+, Jetty 9.4+, Undertow 1.4+
部署方法
1. 项目初始化
bash
# 使用 Spring Initializr 创建项目
curl https://start.spring.io/starter.tgz \
-d type=maven-project \
-d dependencies=web,actuator \
-d bootVersion=2.7.14 \
-o spring-boot-2-app.tar.gz
tar -xzf spring-boot-2-app.tar.gz
cd spring-boot-2-app2. 构建项目
bash
# 使用 Maven
./mvnw clean compile
./mvnw clean package
./mvnw clean spring-boot:run
# 使用 Gradle
./gradlew clean compileJava
./gradlew clean build
./gradlew clean bootRun3. 配置文件说明
Spring Boot 2.x 使用以下配置文件:
application.properties
properties
# 服务器配置
server.port=8080
server.servlet.context-path=/app
# Spring Boot Actuator 配置
management.endpoints.web.exposure.include=health,info,metrics,env
management.endpoint.health.show-details=always
# 日志配置
logging.level.root=INFO
logging.level.org.springframework.web=DEBUG
logging.level.org.hibernate=ERROR
# 数据库配置
spring.datasource.url=jdbc:mysql://localhost:3306/mydb
spring.datasource.username=user
spring.datasource.password=password
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# JPA 配置
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
# Redis 配置
spring.redis.host=localhost
spring.redis.port=6379
spring.redis.database=0application.yml
yaml
server:
port: 8080
servlet:
context-path: /app
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
redis:
host: localhost
port: 6379
database: 0
management:
endpoints:
web:
exposure:
include: health,info,metrics,env
endpoint:
health:
show-details: always4. 打包和部署
bash
# 构建可执行 JAR
./mvnw clean package
# 运行应用
java -jar target/spring-boot-2-app-0.0.1-SNAPSHOT.jar
# 或带参数运行
java -jar target/spring-boot-2-app-0.0.1-SNAPSHOT.jar --server.port=9090二次开发
自定义配置类
创建自定义配置类示例:
src/main/java/com/example/config/AppConfig.java
java
package com.example.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
public class AppConfig {
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
@Bean
public MyCustomService myCustomService() {
return new MyCustomService();
}
}
class MyCustomService {
public String getServiceInfo() {
return "Custom service running on Spring Boot 2.x";
}
}自定义控制器
src/main/java/com/example/controller/CustomController.java
java
package com.example.controller;
import com.example.config.MyCustomService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api")
public class CustomController {
@Autowired
private MyCustomService myCustomService;
@GetMapping("/info")
public String getInfo() {
return "Spring Boot 2.x Application - " + myCustomService.getServiceInfo();
}
@GetMapping("/health")
public String getHealth() {
return "Application is healthy";
}
}自定义过滤器
src/main/java/com/example/filter/CustomFilter.java
java
package com.example.filter;
import org.springframework.stereotype.Component;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Component
public class CustomFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
// 添加自定义头
httpResponse.setHeader("X-Powered-By", "Spring Boot 2.x");
long startTime = System.currentTimeMillis();
chain.doFilter(request, response);
long duration = System.currentTimeMillis() - startTime;
System.out.println("Request processed in " + duration + " ms");
}
}响应式控制器
Spring Boot 2.x 引入了响应式编程支持:
src/main/java/com/example/controller/ReactiveController.java
java
package com.example.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.time.Duration;
import java.util.Arrays;
import java.util.List;
@RestController
@RequestMapping("/reactive")
public class ReactiveController {
@GetMapping("/mono")
public Mono<String> getMono() {
return Mono.just("Hello from Spring Boot 2.x Reactive!");
}
@GetMapping("/flux")
public Flux<String> getFlux() {
List<String> items = Arrays.asList("Item1", "Item2", "Item3");
return Flux.fromIterable(items)
.delayElements(Duration.ofMillis(500));
}
}配置示例
数据库配置示例
application.properties
properties
# MySQL 数据库配置
spring.datasource.url=jdbc:mysql://localhost:3306/springboot2?useSSL=false&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=password
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# HikariCP 连接池配置
spring.datasource.hikari.maximum-pool-size=20
spring.datasource.hikari.minimum-idle=5
spring.datasource.hikari.connection-timeout=20000
spring.datasource.hikari.idle-timeout=300000
spring.datasource.hikari.max-lifetime=1200000
# JPA 配置
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect
spring.jpa.properties.hibernate.current_session_context_class=thread安全配置示例
src/main/java/com/example/config/SecurityConfig.java
java
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.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/", "/home", "/about").permitAll()
.antMatchers("/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.permitAll();
}
@Bean
@Override
public UserDetailsService userDetailsService() {
InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
manager.createUser(User.withDefaultPasswordEncoder()
.username("user")
.password("password")
.roles("USER")
.build());
manager.createUser(User.withDefaultPasswordEncoder()
.username("admin")
.password("admin")
.roles("USER", "ADMIN")
.build());
return manager;
}
}缓存配置示例
src/main/java/com/example/config/CacheConfig.java
java
package com.example.config;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.concurrent.ConcurrentMapCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@EnableCaching
public class CacheConfig {
@Bean
public CacheManager cacheManager() {
return new ConcurrentMapCacheManager("users", "books", "orders");
}
}src/main/java/com/example/service/UserService.java
java
package com.example.service;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
@Service
public class UserService {
@Cacheable("users")
public String getUserById(Long id) {
// 模拟数据库查询
System.out.println("Fetching user from DB for ID: " + id);
return "User Details for ID: " + id;
}
}Demo 示例
REST API 示例
src/main/java/com/example/demo/DemoApplication.java
java
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) {
SpringApplication.run(DemoApplication.class, args);
}
}src/main/java/com/example/demo/model/User.java
java
package com.example.demo.model;
import javax.persistence.*;
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private String name;
@Column(nullable = false, unique = true)
private String email;
public User() {}
public User(String name, String email) {
this.name = name;
this.email = email;
}
// Getters and Setters
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
}src/main/java/com/example/demo/repository/UserRepository.java
java
package com.example.demo.repository;
import com.example.demo.model.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.Optional;
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
Optional<User> findByEmail(String email);
}src/main/java/com/example/demo/controller/UserController.java
java
package com.example.demo.controller;
import com.example.demo.model.User;
import com.example.demo.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Optional;
@RestController
@RequestMapping("/api/users")
public class UserController {
@Autowired
private UserRepository userRepository;
@GetMapping
public ResponseEntity<List<User>> getAllUsers() {
List<User> users = userRepository.findAll();
return new ResponseEntity<>(users, HttpStatus.OK);
}
@GetMapping("/{id}")
public ResponseEntity<User> getUserById(@PathVariable Long id) {
Optional<User> user = userRepository.findById(id);
return user.map(value -> new ResponseEntity<>(value, HttpStatus.OK))
.orElseGet(() -> new ResponseEntity<>(HttpStatus.NOT_FOUND));
}
@PostMapping
public ResponseEntity<User> createUser(@RequestBody User user) {
User savedUser = userRepository.save(user);
return new ResponseEntity<>(savedUser, HttpStatus.CREATED);
}
@PutMapping("/{id}")
public ResponseEntity<User> updateUser(@PathVariable Long id, @RequestBody User userDetails) {
Optional<User> user = userRepository.findById(id);
if (user.isPresent()) {
User updatedUser = user.get();
updatedUser.setName(userDetails.getName());
updatedUser.setEmail(userDetails.getEmail());
userRepository.save(updatedUser);
return new ResponseEntity<>(updatedUser, HttpStatus.OK);
} else {
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
}
@DeleteMapping("/{id}")
public ResponseEntity<HttpStatus> deleteUser(@PathVariable Long id) {
Optional<User> user = userRepository.findById(id);
if (user.isPresent()) {
userRepository.deleteById(id);
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
} else {
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
}
}常见问题和解决方案
1. 启动失败问题
检查日志以确定启动失败的原因:
bash
# 查看启动日志
java -jar app.jar --debug2. 端口冲突问题
properties
# 使用随机端口
server.port=0
# 或者配置多个应用实例
server.port=${PORT:8080}3. 数据库连接问题
确保数据库服务正在运行并正确配置连接参数:
properties
spring.datasource.url=jdbc:mysql://localhost:3306/dbname
spring.datasource.username=username
spring.datasource.password=password
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver4. Actuator 安全配置
在生产环境中限制 actuator 端点的访问:
properties
management.endpoints.web.exposure.include=health,info
management.endpoints.jmx.exposure.include=*
management.endpoint.health.show-details=never性能优化
连接池配置
properties
# HikariCP 配置
spring.datasource.hikari.maximum-pool-size=20
spring.datasource.hikari.minimum-idle=5
spring.datasource.hikari.connection-timeout=20000
spring.datasource.hikari.idle-timeout=300000
spring.datasource.hikari.max-lifetime=1200000
spring.datasource.hikari.leak-detection-threshold=60000JVM 优化
bash
# 推荐的 JVM 参数
JAVA_OPTS="-Xms512m -Xmx1024m \
-XX:+UseG1GC -XX:MaxGCPauseMillis=200 \
-XX:+UseStringDeduplication \
-Djava.awt.headless=true \
-Dfile.encoding=UTF-8"Actuator 配置
properties
# 性能监控配置
management.metrics.export.simple.enabled=true
management.metrics.distribution.percentiles-histogram.http.server.requests=true
management.metrics.distribution.sla.http.server.requests=50ms,100ms,500msDocker 部署示例
Dockerfile
dockerfile
FROM openjdk:11-jre-slim
LABEL maintainer="Your Name <your.email@example.com>"
WORKDIR /app
COPY target/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "/app/app.jar"]
HEALTHCHECK --interval=30s --timeout=3s --start-period=60s --retries=3 \
CMD curl -f http://localhost:8080/actuator/health || exit 1Docker Compose 配置
yaml
version: '3.8'
services:
spring-boot-app:
build: .
ports:
- "8080:8080"
environment:
- SPRING_PROFILES_ACTIVE=docker
- JAVA_OPTS=-Xms512m -Xmx1024m
depends_on:
- mysql
- redis
networks:
- spring-boot-net
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: rootpassword
MYSQL_DATABASE: springboot2
MYSQL_USER: user
MYSQL_PASSWORD: password
ports:
- "3306:3306"
volumes:
- mysql_data:/var/lib/mysql
networks:
- spring-boot-net
redis:
image: redis:6-alpine
ports:
- "6379:6379"
volumes:
- redis_data:/data
networks:
- spring-boot-net
networks:
spring-boot-net:
driver: bridge
volumes:
mysql_data:
redis_data:Kubernetes 部署示例
Deployment 配置
yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: spring-boot-app
labels:
app: spring-boot-app
spec:
replicas: 3
selector:
matchLabels:
app: spring-boot-app
template:
metadata:
labels:
app: spring-boot-app
spec:
containers:
- name: spring-boot
image: spring-boot-2-app:latest
ports:
- containerPort: 8080
env:
- name: SPRING_PROFILES_ACTIVE
value: "kubernetes"
- name: JAVA_OPTS
value: "-Xms512m -Xmx1024m -XX:+UseG1GC"
resources:
requests:
memory: "512Mi"
cpu: "250m"
limits:
memory: "1Gi"
cpu: "500m"
livenessProbe:
httpGet:
path: /actuator/health
port: 8080
initialDelaySeconds: 120
periodSeconds: 30
readinessProbe:
httpGet:
path: /actuator/health
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
---
apiVersion: v1
kind: Service
metadata:
name: spring-boot-service
spec:
selector:
app: spring-boot-app
ports:
- protocol: TCP
port: 80
targetPort: 8080
type: LoadBalancer监控和可观测性
Micrometer 配置
properties
# Micrometer 指标配置
management.metrics.export.prometheus.enabled=true
management.metrics.export.prometheus.step=30s
management.metrics.tags.application=spring-boot-2-app
management.metrics.distribution.percentiles-histogram.http.server.requests=true
management.metrics.distribution.sla.http.server.requests=100ms,500ms,1000ms📝 总结
Spring Boot 2.x 是一个功能强大的现代化框架,提供了企业级的开发体验。它通过自动配置、起步依赖和生产就绪特性,大大简化了 Spring 应用的开发。2.x 版本的重要改进包括对 Java 8+ 的要求、响应式编程支持、性能优化以及对云原生应用的更好支持,使其成为现代企业应用开发的理想选择。