Appearance
Spring Boot Docker Compose 集成指南 🐳
前言:为什么需要 Docker Compose 集成?
在现代微服务开发中,我们经常需要依赖各种外部服务,如数据库、消息队列、缓存等。传统的开发方式需要开发者手动安装和配置这些服务,这不仅繁琐,还容易导致环境不一致的问题。
NOTE
Spring Boot 从 3.1 版本开始,提供了与 Docker Compose 的原生集成支持,让开发者能够更轻松地管理开发环境中的依赖服务。
核心概念理解
Docker Compose 集成的设计哲学
Spring Boot 的 Docker Compose 集成遵循"约定优于配置"的原则:
- 自动发现:Spring Boot 会自动查找项目根目录下的
compose.yaml
或docker-compose.yaml
文件 - 智能连接:自动为容器化的服务创建相应的连接配置
- 生命周期管理:与应用启动/停止同步管理容器的生命周期
实战应用场景
场景一:自定义 JDBC URL 参数
在实际开发中,我们经常需要为数据库连接添加特定的参数,比如 SSL 配置、连接池设置等。
yaml
services:
postgres:
image: 'postgres:15.3'
environment:
- 'POSTGRES_USER=myuser'
- 'POSTGRES_PASSWORD=secret'
- 'POSTGRES_DB=mydb'
ports:
- '5432:5432'
yaml
services:
postgres:
image: 'postgres:15.3'
environment:
- 'POSTGRES_USER=myuser'
- 'POSTGRES_PASSWORD=secret'
- 'POSTGRES_DB=mydb'
ports:
- '5432:5432'
labels:
# 关键配置:自定义 JDBC 参数
org.springframework.boot.jdbc.parameters: 'ssl=true&sslmode=require&connectTimeout=30000'
TIP
使用 org.springframework.boot.jdbc.parameters
标签,Spring Boot 会自动将这些参数附加到 JDBC URL 中,最终生成的连接字符串为: jdbc:postgresql://127.0.0.1:5432/mydb?ssl=true&sslmode=require&connectTimeout=30000
Kotlin 代码示例
kotlin
@RestController
@RequestMapping("/api/users")
class UserController(
private val userRepository: UserRepository
) {
@GetMapping
fun getAllUsers(): List<User> {
// Spring Boot 会自动使用带有 SSL 参数的数据库连接
return userRepository.findAll()
}
@PostMapping
fun createUser(@RequestBody user: User): User {
return userRepository.save(user)
}
}
@Entity
@Table(name = "users")
data class User(
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
val id: Long = 0,
@Column(nullable = false)
val username: String,
@Column(nullable = false)
val email: String
)
@Repository
interface UserRepository : JpaRepository<User, Long>
场景二:多应用间共享服务
在微服务架构中,多个应用可能需要共享同一套基础设施服务(如数据库、Redis 等)。
项目结构示例
microservices-project/
├── shared-services/
│ └── compose.yaml # 共享的服务定义
├── user-service/
│ ├── src/
│ └── application.yml # 用户服务配置
├── order-service/
│ ├── src/
│ └── application.yml # 订单服务配置
└── notification-service/
├── src/
└── application.yml # 通知服务配置
共享服务配置详情
yaml
# shared-services/compose.yaml
services:
postgres:
image: 'postgres:15.3'
environment:
- 'POSTGRES_USER=microservices'
- 'POSTGRES_PASSWORD=secret'
- 'POSTGRES_DB=shared_db'
ports:
- '5432:5432'
volumes:
- postgres_data:/var/lib/postgresql/data
redis:
image: 'redis:7.0'
ports:
- '6379:6379'
command: redis-server --appendonly yes
volumes:
- redis_data:/data
rabbitmq:
image: 'rabbitmq:3.12-management'
ports:
- '5672:5672'
- '15672:15672'
environment:
- 'RABBITMQ_DEFAULT_USER=admin'
- 'RABBITMQ_DEFAULT_PASS=secret'
volumes:
- rabbitmq_data:/var/lib/rabbitmq
volumes:
postgres_data:
redis_data:
rabbitmq_data:
各服务的配置
yaml
spring:
docker:
compose:
file: ../shared-services/compose.yaml # 指向共享服务文件
lifecycle-management: start-only # 只启动,不停止
application:
name: user-service
jpa:
hibernate:
ddl-auto: update
show-sql: true
yaml
spring:
docker:
compose:
file: ../shared-services/compose.yaml # 指向共享服务文件
lifecycle-management: start-only # 只启动,不停止
application:
name: order-service
jpa:
hibernate:
ddl-auto: update
yaml
spring:
docker:
compose:
file: ../shared-services/compose.yaml # 指向共享服务文件
lifecycle-management: start-only # 只启动,不停止
application:
name: notification-service
rabbitmq:
host: localhost
port: 5672
username: admin
password: secret
IMPORTANT
lifecycle-management: start-only
是多应用共享服务的关键配置。如果使用默认的 start-and-stop
,当任何一个应用停止时,共享的服务也会被停止,影响其他正在运行的应用。
实际业务代码示例
kotlin
// 用户服务
@Service
class UserService(
private val userRepository: UserRepository,
private val redisTemplate: RedisTemplate<String, Any>
) {
fun getUserById(id: Long): User? {
// 先从 Redis 缓存中查找
val cacheKey = "user:$id"
val cachedUser = redisTemplate.opsForValue().get(cacheKey) as? User
return cachedUser ?: run {
// 缓存未命中,从数据库查询
val user = userRepository.findById(id).orElse(null)
user?.let {
// 将查询结果缓存到 Redis
redisTemplate.opsForValue().set(cacheKey, it, Duration.ofMinutes(10))
}
user
}
}
}
// 通知服务
@Component
class NotificationListener {
@RabbitListener(queues = ["user.created"])
fun handleUserCreated(userCreatedEvent: UserCreatedEvent) {
// 处理用户创建事件,发送欢迎邮件
println("发送欢迎邮件给用户: ${userCreatedEvent.username}")
// 实际的邮件发送逻辑...
}
}
// 订单服务
@Service
class OrderService(
private val orderRepository: OrderRepository,
private val rabbitTemplate: RabbitTemplate
) {
fun createOrder(order: Order): Order {
val savedOrder = orderRepository.save(order)
// 发布订单创建事件
val orderCreatedEvent = OrderCreatedEvent(
orderId = savedOrder.id,
userId = savedOrder.userId,
amount = savedOrder.amount
)
rabbitTemplate.convertAndSend("order.created", orderCreatedEvent)
return savedOrder
}
}
生命周期管理策略
配置选项对比
配置值 | 行为描述 | 适用场景 |
---|---|---|
start-and-stop (默认) | 应用启动时启动容器,停止时停止容器 | 单应用开发 |
start-only | 应用启动时启动容器,停止时不停止容器 | 多应用共享服务 |
none | 不管理容器生命周期 | 手动管理容器 |
手动管理共享服务
当所有应用都停止后,共享服务仍在运行。可以通过以下命令手动管理:
bash
# 进入共享服务目录
cd shared-services
# 停止所有服务
docker compose stop
# 停止并删除容器(保留数据卷)
docker compose down
# 停止并删除容器和数据卷(谨慎使用)
docker compose down -v
WARNING
使用 docker compose down -v
会删除所有数据卷,这将导致数据库数据丢失。在生产环境或重要开发数据时请谨慎使用。
最佳实践建议
1. 项目结构组织
project-root/
├── compose.yaml # 开发环境服务定义
├── compose.prod.yaml # 生产环境服务定义(如果需要)
├── src/
├── application.yml
└── application-dev.yml # 开发环境特定配置
2. 环境隔离
yaml
services:
postgres:
image: 'postgres:15.3'
environment:
- 'POSTGRES_USER=dev_user'
- 'POSTGRES_PASSWORD=dev_password'
- 'POSTGRES_DB=dev_db'
ports:
- '5432:5432'
# 开发环境可以使用临时卷
volumes:
- postgres_dev_data:/var/lib/postgresql/data
volumes:
postgres_dev_data:
yaml
services:
postgres:
image: 'postgres:15.3'
environment:
- 'POSTGRES_USER=${DB_USER}'
- 'POSTGRES_PASSWORD=${DB_PASSWORD}'
- 'POSTGRES_DB=${DB_NAME}'
ports:
- '5432:5432'
# 生产环境使用持久化存储
volumes:
- /var/lib/postgresql/data:/var/lib/postgresql/data
3. 配置管理
kotlin
@ConfigurationProperties(prefix = "app.database")
data class DatabaseConfig(
val maxConnections: Int = 10,
val connectionTimeout: Duration = Duration.ofSeconds(30),
val enableSsl: Boolean = false
)
@Configuration
@EnableConfigurationProperties(DatabaseConfig::class)
class DataSourceConfiguration(
private val databaseConfig: DatabaseConfig
) {
@Bean
@Primary
fun dataSource(): DataSource {
return HikariDataSource().apply {
maximumPoolSize = databaseConfig.maxConnections
connectionTimeout = databaseConfig.connectionTimeout.toMillis()
if (databaseConfig.enableSsl) {
addDataSourceProperty("ssl", "true")
addDataSourceProperty("sslmode", "require")
}
}
}
}
总结 🎉
Spring Boot 的 Docker Compose 集成为开发者提供了一种优雅的方式来管理开发环境中的依赖服务。通过合理的配置和最佳实践:
✅ 简化环境搭建:一条命令启动所有依赖服务
✅ 提高开发效率:自动化的连接配置和生命周期管理
✅ 增强团队协作:统一的开发环境配置
✅ 支持复杂场景:多应用共享服务、自定义连接参数等
TIP
记住,Docker Compose 集成主要用于开发和测试环境。在生产环境中,建议使用专门的容器编排工具如 Kubernetes 或 Docker Swarm。
通过掌握这些技能,你将能够更高效地进行 Spring Boot 应用开发,专注于业务逻辑而不是环境配置! 🚀