1. 简介

本教程将演示如何使用流行的开源数据库 PostgreSQL 来运行一个 Spring Boot 应用。在之前的文章中,我们介绍了 Docker Compose 如何用于管理多个容器。因此,我们不会单独安装 PostgreSQL,而是使用 Docker Compose 来统一管理 Spring Boot 和 PostgreSQL 的运行环境。

2. 创建 Spring Boot 项目

首先访问 Spring Initializer 创建一个新的 Spring Boot 项目。我们需要添加以下两个依赖项:

  • PostgreSQL Driver
  • Spring Data JPA

下载 ZIP 文件并解压后,尝试运行项目:

./mvnw spring-boot:run

不出意外,你会看到如下错误信息:

***************************
APPLICATION FAILED TO START
***************************

Description:

Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured.

Reason: Failed to determine a suitable driver class

踩坑提示:这是因为没有配置数据源导致的启动失败。

3. 编写 Dockerfile

在使用 Docker Compose 启动 PostgreSQL 之前,我们需要先将 Spring Boot 应用打包成 Docker 镜像。首先将其打包为 JAR 文件:

./mvnw clean package -DskipTests

⚠️ 注意这里跳过了测试,因为没有数据库连接会导致测试失败。

接着,在 src/main/docker 目录下创建 Dockerfile:

FROM adoptopenjdk:11-jre-hotspot
ARG JAR_FILE=*.jar
COPY ${JAR_FILE} application.jar
ENTRYPOINT ["java", "-jar", "application.jar"]

这个 Dockerfile 做了以下几件事:

  • 使用 AdoptOpenJDK 的 Java 11 镜像;
  • 将构建好的 JAR 包复制进容器,并命名为 application.jar
  • 设置入口点,启动应用。

4. 编写 docker-compose.yml

现在来编写 Docker Compose 配置文件 docker-compose.yml,放在 src/main/docker 目录中:

version: '2'

services:
  app:
    image: 'docker-spring-boot-postgres:latest'
    build:
      context: .
    container_name: app
    depends_on:
      - db
    environment:
      - SPRING_DATASOURCE_URL=jdbc:postgresql://db:5432/compose-postgres
      - SPRING_DATASOURCE_USERNAME=compose-postgres
      - SPRING_DATASOURCE_PASSWORD=compose-postgres
      - SPRING_JPA_HIBERNATE_DDL_AUTO=update

  db:
    image: 'postgres:13.1-alpine'
    container_name: db
    environment:
      - POSTGRES_USER=compose-postgres
      - POSTGRES_PASSWORD=compose-postgres

📌 关键点说明:

4.1 应用服务(app)

  • 使用自定义镜像 docker-spring-boot-postgres:latest
  • 构建上下文是当前目录;
  • 依赖于 db 容器,确保先启动数据库;
  • 设置了 Spring Boot 数据源相关的环境变量;
  • Hibernate 自动更新表结构(DDL_AUTO=update)。

4.2 数据库服务(db)

  • 使用官方 PostgreSQL 13.1 Alpine 版本;
  • 用户名和密码均为 compose-postgres
  • 数据库名也通过 URL 指定为 compose-postgres

5. 使用 Docker Compose 启动应用

执行以下命令启动整个服务栈:

docker-compose up

首次运行时会自动构建 Spring Boot 镜像、启动 PostgreSQL 容器,最后运行我们的应用。输出类似如下:

Starting DemoApplication v0.0.1-SNAPSHOT using Java 11.0.9 on f94e79a2c9fc with PID 1 (/application.jar started by root in /)
[...]
Finished Spring Data repository scanning in 28 ms. Found 0 JPA repository interfaces.
[...]
Started DemoApplication in 4.751 seconds (JVM running for 6.512)

如果要停止所有容器,请按 [Ctrl-C],然后执行:

docker-compose down

6. 创建实体类与 Repository

为了操作 PostgreSQL 数据库,我们创建一个简单的客户实体类:

@Entity
@Table(name = "customer")
public class Customer {

    @Id
    @GeneratedValue
    private long id;

    @Column(name = "first_name", nullable = false)
    private String firstName;

    @Column(name = "last_name", nullable = false)
    private String lastName;
}

接着定义对应的 Repository 接口:

public interface CustomerRepository extends JpaRepository<Customer, Long> { }

最后在主类中注入该 Repository 并进行测试:

@SpringBootApplication
public class DemoApplication {
    @Autowired 
    private CustomerRepository repository; 
  
    @EventListener(ApplicationReadyEvent.class)
    public void runAfterStartup() {
        List allCustomers = this.repository.findAll(); 
        logger.info("Number of customers: " + allCustomers.size());
 
        Customer newCustomer = new Customer(); 
        newCustomer.setFirstName("John"); 
        newCustomer.setLastName("Doe"); 
        logger.info("Saving new customer..."); 
        this.repository.save(newCustomer); 
 
        allCustomers = this.repository.findAll(); 
        logger.info("Number of customers: " + allCustomers.size());
    }
}

📌 逻辑说明:

  • 查询当前客户数量(初始为 0);
  • 创建并保存一个新客户;
  • 再次查询,确认客户数量变为 1。

7. 重新构建并再次运行

修改代码后需要重新构建镜像。回到项目根目录执行:

./mvnw clean package -DskipTests
cp target/docker-spring-boot-postgres-0.0.1-SNAPSHOT.jar src/main/docker

然后进入 src/main/docker 目录删除旧镜像以强制重建:

cd src/main/docker
docker-compose down
docker rmi docker-spring-boot-postgres:latest
docker-compose up

此时再次运行,可以看到应用正确识别到了 Repository,并成功保存了一条客户记录:

Finished Spring Data repository scanning in 180 ms. Found 1 JPA repository interfaces.
[...]
Number of customers: 0
Saving new customer...
Number of customers: 1

小结:每次更新代码后记得清理旧镜像再重新构建,避免缓存问题。

8. 总结

这篇文章带你从零开始搭建了一个基于 Spring Boot + PostgreSQL 的 Docker 化开发环境。我们使用 Docker Compose 统一管理服务容器,简化了本地开发流程。

后续你可以继续扩展功能,比如加入 REST Controller 提供 API 接口,或集成 Flyway 做数据库迁移等。

完整源码可以在这里找到:GitHub 示例项目


原始标题:Running Spring Boot with PostgreSQL in Docker Compose | Baeldung