Spring Boot
Spring Boot
概述
Spring Boot是基于Spring Framework的快速应用开发框架,通过"约定优于配置"的理念,大大简化了Spring应用的配置和部署。它提供了自动配置、起步依赖、内嵌服务器等特性,让开发者能够快速构建生产级别的Spring应用。
核心特性
1. 自动配置(Auto Configuration)
Spring Boot根据类路径中的依赖自动配置应用程序。
java
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
// @SpringBootApplication 等价于:
// @Configuration + @EnableAutoConfiguration + @ComponentScan
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
// @SpringBootApplication 等价于:
// @Configuration + @EnableAutoConfiguration + @ComponentScan
2. 起步依赖(Starter Dependencies)
提供一站式的依赖管理,简化Maven/Gradle配置。
xml
<!-- Web应用起步依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 数据库访问起步依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- Web应用起步依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 数据库访问起步依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
3. 内嵌服务器
无需外部服务器,应用可以独立运行。
java
// 默认使用Tomcat,也可以切换到Jetty或Undertow
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
// 应用启动后,内嵌Tomcat服务器开始监听8080端口
}
}
// 默认使用Tomcat,也可以切换到Jetty或Undertow
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
// 应用启动后,内嵌Tomcat服务器开始监听8080端口
}
}
配置管理
application.properties/yml
properties
# application.properties
server.port=8080
spring.datasource.url=jdbc:mysql://localhost:3306/mydb
spring.datasource.username=root
spring.datasource.password=password
spring.jpa.hibernate.ddl-auto=update
# 自定义配置
app.name=MyApplication
app.version=1.0.0
# application.properties
server.port=8080
spring.datasource.url=jdbc:mysql://localhost:3306/mydb
spring.datasource.username=root
spring.datasource.password=password
spring.jpa.hibernate.ddl-auto=update
# 自定义配置
app.name=MyApplication
app.version=1.0.0
yaml
# application.yml
server:
port: 8080
spring:
datasource:
url: jdbc:mysql://localhost:3306/mydb
username: root
password: password
jpa:
hibernate:
ddl-auto: update
app:
name: MyApplication
version: 1.0.0
# application.yml
server:
port: 8080
spring:
datasource:
url: jdbc:mysql://localhost:3306/mydb
username: root
password: password
jpa:
hibernate:
ddl-auto: update
app:
name: MyApplication
version: 1.0.0
配置类绑定
java
@ConfigurationProperties(prefix = "app")
@Component
public class AppProperties {
private String name;
private String version;
// getters and setters
}
// 使用配置
@RestController
public class InfoController {
@Autowired
private AppProperties appProperties;
@GetMapping("/info")
public Map<String, String> getInfo() {
Map<String, String> info = new HashMap<>();
info.put("name", appProperties.getName());
info.put("version", appProperties.getVersion());
return info;
}
}
@ConfigurationProperties(prefix = "app")
@Component
public class AppProperties {
private String name;
private String version;
// getters and setters
}
// 使用配置
@RestController
public class InfoController {
@Autowired
private AppProperties appProperties;
@GetMapping("/info")
public Map<String, String> getInfo() {
Map<String, String> info = new HashMap<>();
info.put("name", appProperties.getName());
info.put("version", appProperties.getVersion());
return info;
}
}
多环境配置
properties
# application.properties
spring.profiles.active=dev
# application-dev.properties
server.port=8080
spring.datasource.url=jdbc:h2:mem:devdb
# application-prod.properties
server.port=80
spring.datasource.url=jdbc:mysql://prod-server:3306/proddb
# application.properties
spring.profiles.active=dev
# application-dev.properties
server.port=8080
spring.datasource.url=jdbc:h2:mem:devdb
# application-prod.properties
server.port=80
spring.datasource.url=jdbc:mysql://prod-server:3306/proddb
常用Starter
Web开发
xml
<!-- Web MVC -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- WebFlux响应式Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<!-- Web MVC -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- WebFlux响应式Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
数据访问
xml
<!-- JPA -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- Redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- MongoDB -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<!-- JPA -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- Redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- MongoDB -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
安全
xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
测试
xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
实际应用示例
RESTful API开发
java
@RestController
@RequestMapping("/api/users")
public class UserController {
@Autowired
private UserService userService;
@GetMapping
public List<User> getAllUsers() {
return userService.findAll();
}
@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(@Valid @RequestBody User user) {
User savedUser = userService.save(user);
return ResponseEntity.status(HttpStatus.CREATED).body(savedUser);
}
@PutMapping("/{id}")
public ResponseEntity<User> updateUser(@PathVariable Long id, @Valid @RequestBody User user) {
user.setId(id);
User updatedUser = userService.update(user);
return ResponseEntity.ok(updatedUser);
}
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteUser(@PathVariable Long id) {
userService.delete(id);
return ResponseEntity.noContent().build();
}
}
@RestController
@RequestMapping("/api/users")
public class UserController {
@Autowired
private UserService userService;
@GetMapping
public List<User> getAllUsers() {
return userService.findAll();
}
@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(@Valid @RequestBody User user) {
User savedUser = userService.save(user);
return ResponseEntity.status(HttpStatus.CREATED).body(savedUser);
}
@PutMapping("/{id}")
public ResponseEntity<User> updateUser(@PathVariable Long id, @Valid @RequestBody User user) {
user.setId(id);
User updatedUser = userService.update(user);
return ResponseEntity.ok(updatedUser);
}
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteUser(@PathVariable Long id) {
userService.delete(id);
return ResponseEntity.noContent().build();
}
}
数据访问层
java
// Entity
@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;
// constructors, getters, setters
}
// Repository
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
Optional<User> findByEmail(String email);
List<User> findByNameContaining(String name);
@Query("SELECT u FROM User u WHERE u.name = ?1")
List<User> findByNameCustom(String name);
}
// Service
@Service
@Transactional
public class UserService {
@Autowired
private UserRepository userRepository;
@Transactional(readOnly = true)
public List<User> findAll() {
return userRepository.findAll();
}
@Transactional(readOnly = true)
public User findById(Long id) {
return userRepository.findById(id).orElse(null);
}
public User save(User user) {
return userRepository.save(user);
}
public User update(User user) {
return userRepository.save(user);
}
public void delete(Long id) {
userRepository.deleteById(id);
}
}
// Entity
@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;
// constructors, getters, setters
}
// Repository
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
Optional<User> findByEmail(String email);
List<User> findByNameContaining(String name);
@Query("SELECT u FROM User u WHERE u.name = ?1")
List<User> findByNameCustom(String name);
}
// Service
@Service
@Transactional
public class UserService {
@Autowired
private UserRepository userRepository;
@Transactional(readOnly = true)
public List<User> findAll() {
return userRepository.findAll();
}
@Transactional(readOnly = true)
public User findById(Long id) {
return userRepository.findById(id).orElse(null);
}
public User save(User user) {
return userRepository.save(user);
}
public User update(User user) {
return userRepository.save(user);
}
public void delete(Long id) {
userRepository.deleteById(id);
}
}
监控和管理
Actuator
xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
properties
# 开启所有端点
management.endpoints.web.exposure.include=*
management.endpoint.health.show-details=always
# 开启所有端点
management.endpoints.web.exposure.include=*
management.endpoint.health.show-details=always
常用端点:
/actuator/health
- 健康检查/actuator/info
- 应用信息/actuator/metrics
- 应用指标/actuator/env
- 环境变量/actuator/beans
- Spring Bean信息
自定义健康检查
java
@Component
public class CustomHealthIndicator implements HealthIndicator {
@Override
public Health health() {
// 执行健康检查逻辑
boolean isHealthy = checkExternalService();
if (isHealthy) {
return Health.up()
.withDetail("service", "Available")
.build();
} else {
return Health.down()
.withDetail("service", "Unavailable")
.build();
}
}
private boolean checkExternalService() {
// 实际的健康检查逻辑
return true;
}
}
@Component
public class CustomHealthIndicator implements HealthIndicator {
@Override
public Health health() {
// 执行健康检查逻辑
boolean isHealthy = checkExternalService();
if (isHealthy) {
return Health.up()
.withDetail("service", "Available")
.build();
} else {
return Health.down()
.withDetail("service", "Unavailable")
.build();
}
}
private boolean checkExternalService() {
// 实际的健康检查逻辑
return true;
}
}
测试
单元测试
java
@ExtendWith(SpringExtension.class)
@SpringBootTest
class UserServiceTest {
@Autowired
private UserService userService;
@MockBean
private UserRepository userRepository;
@Test
void testFindById() {
// Given
User user = new User("John", "[email protected]");
when(userRepository.findById(1L)).thenReturn(Optional.of(user));
// When
User result = userService.findById(1L);
// Then
assertThat(result).isNotNull();
assertThat(result.getName()).isEqualTo("John");
}
}
@ExtendWith(SpringExtension.class)
@SpringBootTest
class UserServiceTest {
@Autowired
private UserService userService;
@MockBean
private UserRepository userRepository;
@Test
void testFindById() {
// Given
User user = new User("John", "[email protected]");
when(userRepository.findById(1L)).thenReturn(Optional.of(user));
// When
User result = userService.findById(1L);
// Then
assertThat(result).isNotNull();
assertThat(result.getName()).isEqualTo("John");
}
}
集成测试
java
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
class UserControllerIntegrationTest {
@Autowired
private TestRestTemplate restTemplate;
@Test
void testCreateUser() {
// Given
User user = new User("Jane", "[email protected]");
// When
ResponseEntity<User> response = restTemplate.postForEntity("/api/users", user, User.class);
// Then
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.CREATED);
assertThat(response.getBody().getName()).isEqualTo("Jane");
}
}
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
class UserControllerIntegrationTest {
@Autowired
private TestRestTemplate restTemplate;
@Test
void testCreateUser() {
// Given
User user = new User("Jane", "[email protected]");
// When
ResponseEntity<User> response = restTemplate.postForEntity("/api/users", user, User.class);
// Then
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.CREATED);
assertThat(response.getBody().getName()).isEqualTo("Jane");
}
}
Web层测试
java
@WebMvcTest(UserController.class)
class UserControllerTest {
@Autowired
private MockMvc mockMvc;
@MockBean
private UserService userService;
@Test
void testGetUser() throws Exception {
// Given
User user = new User("John", "[email protected]");
when(userService.findById(1L)).thenReturn(user);
// When & Then
mockMvc.perform(get("/api/users/1"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.name").value("John"))
.andExpect(jsonPath("$.email").value("[email protected]"));
}
}
@WebMvcTest(UserController.class)
class UserControllerTest {
@Autowired
private MockMvc mockMvc;
@MockBean
private UserService userService;
@Test
void testGetUser() throws Exception {
// Given
User user = new User("John", "[email protected]");
when(userService.findById(1L)).thenReturn(user);
// When & Then
mockMvc.perform(get("/api/users/1"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.name").value("John"))
.andExpect(jsonPath("$.email").value("[email protected]"));
}
}
部署
打包
bash
# Maven
mvn clean package
# Gradle
./gradlew build
# Maven
mvn clean package
# Gradle
./gradlew build
运行
bash
# 直接运行JAR
java -jar myapp.jar
# 指定配置文件
java -jar myapp.jar --spring.config.location=classpath:/application-prod.yml
# 指定Profile
java -jar myapp.jar --spring.profiles.active=prod
# 直接运行JAR
java -jar myapp.jar
# 指定配置文件
java -jar myapp.jar --spring.config.location=classpath:/application-prod.yml
# 指定Profile
java -jar myapp.jar --spring.profiles.active=prod
Docker部署
dockerfile
FROM openjdk:11-jre-slim
COPY target/myapp.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "/app.jar"]
FROM openjdk:11-jre-slim
COPY target/myapp.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "/app.jar"]
最佳实践
- 合理使用Starter:选择合适的starter,避免引入不必要的依赖
- 配置外部化:使用配置文件管理环境相关配置
- 使用Profile:为不同环境创建不同的配置文件
- 监控和日志:集成Actuator和日志框架
- 安全配置:生产环境中保护敏感端点
- 测试覆盖:编写充分的单元测试和集成测试
- 性能优化:合理配置JVM参数和连接池
- 文档化:使用Swagger等工具生成API文档
与微服务的关系
Spring Boot为微服务架构提供了理想的基础:
- 独立部署:每个微服务都是独立的可执行JAR
- 快速启动:内嵌服务器支持快速启动和停止
- 配置管理:支持外部化配置和多环境部署
- 监控支持:Actuator提供了丰富的监控端点
总结
Spring Boot通过自动配置、起步依赖等特性,大大简化了Spring应用的开发和部署。它让开发者能够专注于业务逻辑,而不是繁琐的配置。掌握Spring Boot是现代Java企业级开发的必备技能,也是学习Spring Cloud微服务架构的基础。