目录
- 为什么使用 Docker 进行 Java 开发?
- 核心概念简介
- 简单的 Maven/Gradle 项目构建
- 交互式 Java 开发环境(推荐)
- 多服务项目(如 Spring Boot + MySQL + Redis)
- Docker Compose 深入
- 最佳实践与进阶技巧
为什么使用 Docker 进行 Java 开发?
- 环境一致性:解决了 "在我电脑上是好的" (It works on my machine) 问题,无论你用的是 macOS, Windows 还是 Linux,Docker 容器都能提供一个完全相同的运行环境。
- 快速环境搭建:无需在本地安装 JDK、Maven、Gradle 等工具,通过一个
docker pull命令即可获取所需环境。 - 资源隔离与清理:项目之间互不干扰,用完即删,不会污染本地系统。
- 简化团队协作:新成员加入项目,只需克隆代码和运行
docker-compose up,就能快速启动整个开发环境。 - 平滑过渡到生产:开发环境使用的 Dockerfile 可以直接用于构建生产环境的镜像,实现 DevOps 的无缝衔接。
核心概念简介
在开始之前,你需要了解几个 Docker 核心概念:

- Dockerfile:一个文本文件,用于定义如何构建一个自定义的 Docker 镜像,它包含了构建镜像所需的所有指令(如 FROM, COPY, RUN, CMD 等)。
- Docker Image (镜像):一个只读的模板,包含了创建 Docker 容器所需要的文件和配置,你可以把它看作是面向对象编程中的“类”。
- Docker Container (容器):镜像的运行实例,它是轻量级、可执行的独立软件包,包含了应用程序及其所有依赖,你可以把它看作是“类的实例”。
- Docker Compose:一个用于定义和运行多容器 Docker 应用程序的工具,通过一个
docker-compose.yml文件,你可以配置所有服务(如你的应用、数据库、缓存等),然后用一个命令来启动和管理它们。
场景一:简单的 Maven/Gradle 项目构建
这个场景适合那些只需要在 CI/CD 流程或命令行中构建项目的开发者。
步骤 1: 创建项目结构
my-java-project/
├── src/
│ └── main/
│ └── java/
│ └── com/
│ └── example/
│ └── App.java
├── pom.xml (或 build.gradle)
└── Dockerfile
步骤 2: 编写 Dockerfile
这是一个高效的 Dockerfile,它利用了 Docker 的多阶段构建来减小最终镜像的体积。
# 阶段一:构建阶段 # 使用官方的 Maven 镜像作为基础镜像 FROM maven:3.8.6-openjdk-17 AS builder # 设置工作目录 WORKDIR /app # 将 pom.xml 复制到工作目录(利用 Docker 缓存) # 这一步会在第一次构建后缓存,pom.xml 不变,后续构建会很快 COPY pom.xml . # 将 src 目录复制到工作目录 COPY src ./src # 执行 Maven 构建命令 # -DskipTests: 跳过测试 mvn clean package -DskipTests
步骤 3: 构建和运行
-
构建镜像: 在
my-java-project目录下,打开终端,运行:docker build -t my-java-app .
-t my-java-app是给你的镜像打一个标签(名字)。
(图片来源网络,侵删) -
运行容器:
docker run -it --rm my-java-app
这会运行你的 JAR 文件,并打印出输出。
场景二:交互式 Java 开发环境(推荐)
这个场景更适合日常开发,你希望在本地 IDE(如 IntelliJ IDEA, VS Code)中编写代码,同时利用 Docker 来管理依赖和运行环境。
方法:使用 Docker Volume 进行代码同步
我们将创建一个容器,它会挂载你的本地项目代码,这样你可以在 IDE 中修改代码,容器内的文件也会实时更新。

步骤 1: 创建 Dockerfile (用于开发环境)
这个 Dockerfile 只负责提供一个开发环境,不包含构建逻辑。
# 使用一个包含 JDK 和 Maven 的官方镜像 FROM maven:3.8.6-openjdk-17 # 设置工作目录 WORKDIR /app # 安装一些可能用到的工具,如 curl, vim RUN apt-get update && apt-get install -y curl vim # (可选)设置一个默认的 Maven 配置 # COPY settings.xml /usr/share/maven/conf/settings.xml # 暴露一个常用的端口(如果你的应用是 Web 应用) EXPOSE 8080 # 设置一个启动后执行的命令(可以是你应用的启动命令) # 这里我们让它保持运行,等待你进入容器后手动操作 CMD ["tail", "-f", "/dev/null"]
步骤 2: 运行开发容器
在项目根目录(包含 pom.xml 和 src 的目录)下运行以下命令:
docker run -it --rm \ --name java-dev-container \ -p 8080:8080 \ # 将容器的 8080 端口映射到主机的 8080 端口 -v $(pwd):/app \ # 将当前目录挂载到容器的 /app 目录 -v ~/.m2:/root/.m2 \ # 将本地的 Maven 仓库挂载到容器中,实现依赖缓存 my-java-dev-image \ /bin/bash
命令解释:
-it: 以交互模式运行并分配一个伪终端。--rm: 容器停止后自动删除。--name: 给容器一个友好的名字。-p 8080:8080: 端口映射,方便你在主机上访问应用。-v $(pwd):/app: 最关键的一步,将你当前的项目目录挂载到容器中,你在主机上修改任何文件,容器内都会立刻生效。-v ~/.m2:/root/.m2: 将你本地的 Maven 仓库挂载进去,这样第一次下载依赖后,后续构建会非常快,因为依赖已经缓存了。my-java-dev-image: 你之前构建的镜像名称。/bin/bash: 容器启动后执行的命令,这里我们进入一个 bash shell。
步骤 3: 在容器内开发
-
运行上述命令后,你就会进入容器的 bash 终端。
-
你会发现当前目录就是
/app,并且能看到你所有的项目文件。 -
现在你可以直接在容器内执行 Maven 命令:
# 编译项目 mvn compile # 运行测试 mvn test # 打包项目 mvn package # 直接运行 Spring Boot 应用 java -jar target/your-app-name.jar
-
你也可以使用
docker exec命令在运行中的容器里执行命令:# 进入正在运行的容器 docker exec -it java-dev-container /bin/bash
场景三:多服务项目(如 Spring Boot + MySQL + Redis)
这是现代微服务架构的典型场景,Docker Compose 是解决这个问题的利器。
假设你的项目结构如下:
my-spring-app/
├── docker-compose.yml
├── spring-boot-app/
│ ├── Dockerfile
│ ├── pom.xml
│ └── src/
└── README.md
步骤 1: 编写 docker-compose.yml
这个文件定义了整个应用栈。
version: '3.8'
services:
# 你的 Spring Boot 应用服务
app:
build: ./spring-boot-app # 指定 Dockerfile 所在目录
ports:
- "8080:8080" # 映射端口
environment:
# 将数据库连接信息作为环境变量传递给应用
- SPRING_DATASOURCE_URL=jdbc:mysql://db:3306/mydb?useSSL=false&serverTimezone=UTC
- SPRING_DATASOURCE_USERNAME=root
- SPRING_DATASOURCE_PASSWORD=password
- SPRING_REDIS_HOST=redis
depends_on:
- db
- redis
volumes:
- ./spring-boot-app:/app # 挂载代码,支持热重载(如果你的应用支持)
- ~/.m2:/root/.m2 # 挂载 Maven 仓库
# 如果你使用 JRebel 或 XRebel 进行热部署,可以添加以下参数
# command: ["java", "-agentlib:nativeagent=native-image-agent=config-output-dir=/path/to/output", "-jar", "app.jar"]
# MySQL 数据库服务
db:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: password
MYSQL_DATABASE: mydb
volumes:
- db-data:/var/lib/mysql # 持久化数据
ports:
- "3306:3306"
# Redis 缓存服务
redis:
image: redis:7-alpine
ports:
- "6379:6379"
# 定义数据卷,用于数据持久化
volumes:
db-data:
步骤 2: 编写应用的 Dockerfile
在 spring-boot-app 目录下创建一个简单的 Dockerfile。
FROM openjdk:17-jdk-slim WORKDIR /app # 复制并运行 JAR 文件 COPY target/*.jar app.jar EXPOSE 8080 ENTRYPOINT ["java", "-jar", "app.jar"]
步骤 3: 启动所有服务
在 my-spring-app 目录下,运行:
# -d 表示在后台运行 docker-compose up --build -d
--build: 每次启动都重新构建app服务的镜像。-d: Detached mode,后台运行。
你的 Spring Boot 应用、MySQL 和 Redis 都已经启动并相互连接了!
你可以使用 docker-compose ps 查看服务状态,使用 docker-compose logs -f app 查看应用的日志。
要停止并删除所有容器和网络,运行:
docker-compose down
如果还想删除数据卷,使用:
docker-compose down -v
Docker Compose 深入
- 网络:默认情况下,Docker Compose 会创建一个网络,所有服务都可以通过服务名互相发现,在
app服务中,可以通过http://db:3306访问数据库db。 - 环境变量:可以通过
environment或env_file来为服务注入环境变量。 - 数据卷:用于持久化数据(如数据库数据)或共享代码/配置,有两种类型:命名卷(
volumes)和绑定挂载(volumes中的主机路径)。
最佳实践与进阶技巧
- 使用
.dockerignore:就像.gitignore一样,创建一个.dockerignore文件来排除不必要的文件(如.git,target,IDE文件),以加快构建速度并减小镜像体积。.git .idea target/ *.log - 多阶段构建:如场景一所示,这是减小最终镜像体积的最佳实践,一个阶段用于构建,另一个阶段用于运行,只包含运行时所需的依赖。
- 使用非 root 用户:为了安全,最好在 Dockerfile 中创建一个非 root 用户来运行应用。
RUN groupadd -r spring && useradd -r -g spring spring USER spring
- IDE 集成:IntelliJ IDEA 和 VS Code 对 Docker 有出色的原生支持,你可以直接在 IDE 中管理容器、查看日志、甚至调试容器内的应用。
- 热部署:
- 对于传统的 WAR 应用,可以在
docker run命令中挂载target目录。 - 对于 Spring Boot JAR 应用,可以利用其内置的 DevTools(需要重启)或更高级的工具如 JRebel/XRebel。
- 在 Docker Compose 中,修改代码后,应用通常不会自动重启,你可能需要配置文件监听和重启策略(如
watchtower工具或 IDE 的功能)。
- 对于传统的 WAR 应用,可以在
| 场景 | 核心工具 | 适用情况 | 优点 |
|---|---|---|---|
| 简单构建 | Dockerfile + docker build/run |
CI/CD 流程、一次性构建 | 简单、直接、隔离性好 |
| 交互式开发 | Dockerfile + docker run + Volume |
日常编码、需要本地 IDE | 环境隔离、依赖共享、代码同步 |
| 多服务应用 | Dockerfile + docker-compose.yml |
微服务、全栈项目 | 统一管理、一键启停、网络互通 |
对于个人开发者或小型团队,场景二(交互式开发) 是最灵活和高效的,对于复杂的项目,场景三(Docker Compose) 是行业标准。
希望这份详细的指南能帮助你顺利地开始在 Docker 环境中进行 Java 开发!
