Linux第22篇:用Docker容器化你的Java SaaS应用:一次构建,随处运行

一句话定义:本文系统讲解如何使用Docker将Java SaaS应用及其依赖的MySQL、Redis等中间件进行全容器化部署,通过Dockerfile镜像构建与docker-compose容器编排,实现"一次构建,随处运行"的标准化交付。

一、引言:从"手工部署"到"一键启动"

在之前的15篇文章中,我们走完了从Linux基础到Java环境搭建、从Nginx配置到MySQL/Redis部署的全流程。这个过程你肯定深有体会------每部署一套新环境,都要重复一遍:装JDK、配MySQL、装Redis、改配置文件、启动服务...... 少说也要半天时间。

如果有一天服务器宕机了要迁移,或者要把应用从测试环境部署到生产环境,难道要重新来一遍?

Docker就是来解决这个问题的。

Docker的核心思想是**"一次构建,随处运行"** ------把应用连同它依赖的所有东西(JDK、配置文件、环境变量)打包成一个镜像 ,这个镜像可以在任何安装了Docker的服务器上直接运行成容器 。开发环境跑通了,镜像推到生产环境,行为完全一致------"在我机器上是好的"这句话将彻底成为历史

在Java SaaS部署的全链路中(第13篇JDK → 第14篇应用部署 → 第15篇Nginx → 第16篇数据库 → 第17篇Redis → 本篇Docker → 第19篇性能调优),Docker是从"手工运维"走向"自动化运维"的分水岭。掌握了Docker,你就掌握了现代软件交付的"通用语言"。

二、Docker核心概念:镜像、容器、仓库

在动手之前,花3分钟搞清楚三个核心概念------这是理解一切Docker操作的基础

概念 通俗理解 类比
镜像(Image) 一个只读的"模板",包含了运行应用所需的一切(代码、运行时、系统工具、库) 类似于安装光盘/ISO文件
容器(Container) 镜像的运行实例,一个隔离的进程 类似于用光盘安装好的操作系统
仓库(Repository) 存储和分发镜像的地方 类似于应用商店/代码仓库

关系镜像运行容器。你可以从仓库拉取别人做好的镜像,也可以自己用Dockerfile构建镜像。一个镜像可以启动无数个容器实例。

三、在Linux上安装Docker

3.1 安装前的系统检查

为什么这样写:Docker对操作系统内核版本有明确要求。很多人在老旧的CentOS 7上装Docker,结果因为内核版本太低(❤️.10)导致overlay2存储驱动无法使用,容器启动各种报错。先检查再安装,能避免90%的坑。

踩过的坑

  • 坑1:系统里装了旧版Docker(如docker.io)没卸载干净,与新版本冲突
  • 坑2:没加当前用户到docker组,每次执行docker命令都要sudo

注意事项

  • Docker要求Linux内核版本不低于3.10
  • 生产环境推荐Rocky Linux 9 / Ubuntu 22.04 LTS及以上
  • 以下同时给出Rocky Linux/CentOSUbuntu两套安装命令

代码块:环境检查与旧版本清理

bash 复制代码
# 1. 检查内核版本(必须 >= 3.10)
uname -r

# 2. 检查操作系统版本
cat /etc/os-release

# 3. 卸载旧版本Docker(如有)
# Rocky Linux / CentOS:
sudo dnf remove -y docker docker-client docker-client-latest \
  docker-common docker-latest docker-latest-logrotate docker-logrotate docker-engine

# Ubuntu / Debian:
sudo apt remove -y docker docker-engine docker.io containerd runc

执行后说明uname -r应输出类似5.14.0-284.el9.x86_64的内核版本。如果内核低于3.10(如CentOS 7的3.10.0),虽然能满足最低要求,但建议升级到更新的发行版以获得更好的容器支持。

3.2 安装Docker Engine(双系统适配)

为什么这样写:Docker官方提供了针对各Linux发行版的官方仓库,这是生产环境最推荐的安装方式------能自动处理依赖、方便后续升级、来源可靠。不要用系统默认仓库里的旧版本Docker。

踩过的坑

  • 坑:Rocky Linux用dnf install docker装的是Podman而不是Docker
  • 坑:Ubuntu用apt install docker.io装的是旧版,缺少新特性

注意事项

  • 以下使用Docker官方仓库安装,确保版本最新
  • 如需配置国内镜像加速器以提升拉取速度,见3.3节

代码块:Rocky Linux 9 / CentOS 9 安装Docker

bash 复制代码
# 1. 安装必要依赖
sudo dnf install -y dnf-plugins-core

# 2. 添加Docker官方YUM仓库
sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo

# 3. 安装Docker Engine及相关组件
sudo dnf install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

# 4. 启动Docker服务并设置开机自启
sudo systemctl start docker
sudo systemctl enable docker

# 5. 验证安装
sudo docker --version

代码块:Ubuntu 22.04 / 24.04 安装Docker

bash 复制代码
# 1. 更新软件包列表并安装依赖
sudo apt update
sudo apt install -y ca-certificates curl

# 2. 添加Docker官方GPG密钥
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc

# 3. 添加Docker官方APT仓库
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] \
  https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" \
  | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

# 4. 安装Docker Engine
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

# 5. 启动Docker服务并验证
sudo systemctl start docker
sudo systemctl enable docker
sudo docker --version

执行后说明 :安装完成后,sudo docker --version应输出类似Docker version 27.0.3的版本信息。Docker服务已启动并设置为开机自启。

3.3 配置用户权限与镜像加速(非必须但强烈推荐)

为什么这样写 :每次执行docker命令都要加sudo很烦人,把当前用户加入docker组可以省去这个麻烦。另外,在国内访问Docker Hub拉取镜像速度很慢,配置镜像加速器能大幅提升体验。

注意事项

  • 加入docker组后需要重新登录才能生效
  • 镜像加速器地址请咨询你的云服务商(阿里云、腾讯云、华为云均提供免费加速器)

代码块:用户权限配置与镜像加速

bash 复制代码
# 1. 将当前用户加入docker组(避免每次sudo)
sudo usermod -aG docker $USER
# ⚠️ 执行后需要退出重新登录才能生效

# 2. 配置Docker守护进程(/etc/docker/daemon.json)
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json << 'EOF'
{
  "registry-mirrors": [
    "https://your-mirror.aliyuncs.com"   # 替换为你的镜像加速器地址
  ],
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  },
  "storage-driver": "overlay2"
}
EOF

# 3. 重启Docker使配置生效
sudo systemctl daemon-reload
sudo systemctl restart docker

# 4. 验证配置
docker info | grep -A 5 "Registry Mirrors"

执行后说明docker info会显示当前的镜像加速器配置。如果看到你配置的加速器地址,说明生效了。storage-driver: overlay2是当前最推荐的存储驱动,性能和稳定性都很好。

四、编写Dockerfile:把Java应用变成镜像

4.1 为什么需要多阶段构建

为什么这样写 :一个Java应用的Dockerfile写得好不好,最直接的衡量标准就是镜像体积。一个未经优化的Spring Boot镜像动辄500MB-1GB,拉取慢、传输慢、浪费存储空间。而采用多阶段构建(Multi-stage Build)后,镜像可以瘦身到100MB左右。

多阶段构建的核心思想是

  • 第一阶段(构建阶段) :用包含完整JDK和Maven的"重型"镜像来编译打包代码
  • 第二阶段(运行阶段) :只把打好的jar包复制到一个"轻型"镜像(如JRE slim)中运行

最终镜像里只包含运行时需要的东西------没有源码、没有Maven、没有编译工具,体积大幅缩小,安全性也更高。

踩过的坑

  • 坑1:把编译和运行放在一个阶段,镜像里塞满了Maven依赖和源码,体积1GB+
  • 坑2:用了openjdk:17(约400MB)而不是eclipse-temurin:17-jre-alpine(约80MB)
  • 坑3:没有写.dockerignore,把target/.git/等无用文件也打进了镜像

注意事项

  • 本文示例基于Spring Boot 3.x + JDK 17
  • 基础镜像推荐使用eclipse-temurin:17-jre-alpine------基于Alpine Linux(仅5MB),加上JRE后总大小约80MB
  • 不要使用已弃用的openjdk官方镜像

4.2 生产级Dockerfile完整示例

代码块:多阶段构建Dockerfile(生产环境推荐)

dockerfile 复制代码
# ============================================================
# 第一阶段:构建阶段(builder)
# 使用包含完整JDK和Maven的镜像来编译打包
# ============================================================
FROM maven:3.9-eclipse-temurin-17-alpine AS builder

# 设置工作目录
WORKDIR /build

# 先复制pom.xml------利用Docker层缓存,依赖不变时不重复下载
COPY pom.xml .
RUN mvn dependency:go-offline -B

# 再复制源代码并打包
COPY src ./src
RUN mvn package -DskipTests -B

# ============================================================
# 第二阶段:运行阶段(最终镜像)
# 只复制jar包,使用轻量级JRE镜像
# ============================================================
FROM eclipse-temurin:17-jre-alpine

# 创建应用运行用户(非root,安全加固)
RUN addgroup -S appgroup && adduser -S appuser -G appgroup

# 设置工作目录
WORKDIR /app

# 从构建阶段复制jar包
COPY --from=builder /build/target/*.jar ./app.jar

# 创建挂载点(用于日志和配置的外部挂载)
VOLUME /app/logs
VOLUME /app/config

# 暴露应用端口(根据你的应用调整)
EXPOSE 8080

# 切换到非root用户
USER appuser

# JVM参数优化(容器环境专用)
ENV JAVA_OPTS="-XX:+UseContainerSupport \
  -XX:MaxRAMPercentage=75.0 \
  -XX:InitialRAMPercentage=50.0 \
  -XX:+HeapDumpOnOutOfMemoryError \
  -XX:HeapDumpPath=/app/logs/heapdump.hprof \
  -Djava.security.egd=file:/dev/./urandom"

# 启动命令
ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar /app/app.jar"]

执行后说明:这个Dockerfile有几个关键设计:

  1. 分层缓存优化 :先复制pom.xml并下载依赖(dependency:go-offline),再复制源码。只要pom.xml不变,Maven依赖就不会重新下载,构建速度提升80%。

  2. 多阶段构建 :构建阶段用Maven镜像(约500MB),最终运行阶段只用JRE Alpine镜像(约80MB),最终镜像体积约90MB

  3. 非root运行USER appuser让容器内的Java进程不以root身份运行,符合安全最佳实践。

  4. 容器感知JVM参数-XX:+UseContainerSupport(JDK 10+默认开启)让JVM能识别容器的内存限制。-XX:MaxRAMPercentage=75.0表示JVM堆内存最多占容器内存的75%------如果容器内存限制为2GB,堆最大为1.5GB,留有500MB给元空间和系统开销。

  5. VOLUME声明 :声明/app/logs/app/config为挂载点,方便在宿主机上持久化日志和覆盖配置文件。

4.3 编写.dockerignore------别把"垃圾"打包进镜像

为什么这样写docker build默认会把当前目录下所有文件发送给Docker守护进程来构建镜像。如果不加限制,target/(几百MB的编译产物)、.git/(整个仓库历史)、node_modules/等都会被塞进构建上下文,拖慢构建速度,还可能泄露源码

代码块:.dockerignore文件

dockerignore 复制代码
# Git相关
.git/
.gitignore

# 构建产物
target/
*.jar
*.war
*.log

# IDE相关
.idea/
*.iml
.vscode/
.settings/
.classpath
.project

# 系统文件
.DS_Store
Thumbs.db

# 容器相关(避免递归)
Dockerfile
.dockerignore
docker-compose*.yml

# 其他
*.md
README*

执行后说明.dockerignore的语法和.gitignore完全一样。配置好后,docker build只会把必要的源码和pom.xml发送给Docker守护进程,构建速度和安全性都得到保障。

五、构建镜像与运行容器

5.1 构建镜像

为什么这样写 :Dockerfile写好了,现在要把它"变成"一个真正的镜像。docker build命令就是做这个的。

踩过的坑

  • 坑:忘了加-t参数给镜像打标签,构建出来的镜像叫<none>,根本认不出来
  • 坑:在项目根目录执行docker build .时,没有.dockerignore,构建上下文巨大

注意事项

  • -t参数给镜像起名,格式为仓库名/镜像名:标签
  • 末尾的.表示构建上下文为当前目录

代码块:构建镜像

bash 复制代码
# 1. 在项目根目录执行构建
cd /path/to/your-java-project

# 2. 构建镜像(给镜像打上标签)
docker build -t myapp:1.0.0 .

# 3. 查看已构建的镜像
docker images | grep myapp

# 4. 查看镜像分层历史(理解镜像的构成)
docker history myapp:1.0.0

执行后说明docker images应显示myapp镜像,大小约90MB。docker history会展示镜像的每一层------你会看到第一层是Alpine基础镜像(约5MB),然后是JRE层,最后是app.jar层。每一层都是一个只读文件系统,层与层之间复用,这就是Docker镜像高效的原因。

5.2 运行容器

为什么这样写:镜像构建好了,现在要把它"跑起来"------这就是容器。

踩过的坑

  • 坑:没映射端口(-p),容器里的8080端口外界访问不到
  • 坑:没设置--restart策略,容器崩溃后不会自动重启
  • 坑:容器内存限制没设,JVM可能吃光宿主机内存

代码块:运行容器

bash 复制代码
# 1. 基本运行(前台运行,用于调试)
docker run -p 8080:8080 myapp:1.0.0

# 2. 后台运行 + 重启策略 + 资源限制(生产环境推荐)
docker run -d \
  --name myapp \
  --restart=unless-stopped \
  -p 8080:8080 \
  -m 2g \
  --memory-reservation 1.5g \
  -e "SPRING_PROFILES_ACTIVE=prod" \
  -v /data/myapp/logs:/app/logs \
  -v /data/myapp/config:/app/config \
  myapp:1.0.0

# 3. 查看容器运行状态
docker ps

# 4. 查看容器日志
docker logs -f myapp

# 5. 进入容器内部(调试用)
docker exec -it myapp sh

执行后说明

  • -d:后台运行(detach模式)
  • --name:给容器起名,方便后续管理
  • --restart=unless-stopped:容器意外退出时自动重启,除非手动停止
  • -p 8080:8080:将宿主机的8080端口映射到容器的8080端口
  • -m 2g:限制容器最大使用内存为2GB
  • --memory-reservation 1.5g:软性内存预留
  • -e:设置环境变量,这里激活了Spring Boot的prod配置文件
  • -v:挂载卷,将宿主机目录映射到容器内,实现日志持久化和配置外部化

关键提示-m 2g和JVM的-XX:MaxRAMPercentage=75.0要配合使用------容器内存2GB,JVM堆最大1.5GB,留500MB给JVM元空间和系统开销。

六、docker-compose:一键启动整个SaaS应用栈

6.1 为什么需要docker-compose

为什么这样写 :到目前为止,我们只容器化了Java应用本身。但一个完整的SaaS应用还需要MySQL、Redis、Nginx等中间件。如果每个服务都手动docker run,不但命令冗长,还要处理服务之间的网络连通、启动顺序等问题。

docker-compose 就是来解决这个问题的------它用一个docker-compose.yml文件定义所有服务,然后一条命令启动全部

踩过的坑

  • 坑:服务之间的依赖关系没配置(depends_on),应用启动时数据库还没就绪
  • 坑:没配置健康检查,容器显示"running"但服务实际不可用

6.2 docker-compose.yml完整示例

代码块:docker-compose.yml(Java应用 + MySQL + Redis)

yaml 复制代码
version: '3.8'

services:
  # ============ MySQL 数据库 ============
  mysql:
    image: mysql:8.0
    container_name: saas-mysql
    restart: unless-stopped
    environment:
      MYSQL_ROOT_PASSWORD: root_strong_passwd
      MYSQL_DATABASE: saas_db
      MYSQL_USER: saas_user
      MYSQL_PASSWORD: saas_passwd
      TZ: Asia/Shanghai
    ports:
      - "3306:3306"
    volumes:
      - mysql_data:/var/lib/mysql
      - ./init.sql:/docker-entrypoint-initdb.d/init.sql
    command:
      - --character-set-server=utf8mb4
      - --collation-server=utf8mb4_unicode_ci
      - --max_connections=500
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
      interval: 10s
      timeout: 5s
      retries: 5
    networks:
      - saas-network

  # ============ Redis 缓存 ============
  redis:
    image: redis:7.0-alpine
    container_name: saas-redis
    restart: unless-stopped
    ports:
      - "6379:6379"
    volumes:
      - redis_data:/data
    command: redis-server --appendonly yes --requirepass redis_strong_passwd
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s
      timeout: 5s
      retries: 5
    networks:
      - saas-network

  # ============ Java 应用 ============
  app:
    build:
      context: .
      dockerfile: Dockerfile
    image: myapp:1.0.0
    container_name: saas-app
    restart: unless-stopped
    ports:
      - "8080:8080"
    environment:
      SPRING_PROFILES_ACTIVE: docker
      SPRING_DATASOURCE_URL: jdbc:mysql://mysql:3306/saas_db?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai
      SPRING_DATASOURCE_USERNAME: saas_user
      SPRING_DATASOURCE_PASSWORD: saas_passwd
      SPRING_REDIS_HOST: redis
      SPRING_REDIS_PORT: 6379
      SPRING_REDIS_PASSWORD: redis_strong_passwd
    volumes:
      - app_logs:/app/logs
    depends_on:
      mysql:
        condition: service_healthy
      redis:
        condition: service_healthy
    networks:
      - saas-network

# ============ 卷定义 ============
volumes:
  mysql_data:
  redis_data:
  app_logs:

# ============ 网络定义 ============
networks:
  saas-network:
    driver: bridge

执行后说明:这个docker-compose.yml定义了三个服务:

  1. mysql:使用MySQL 8.0镜像,配置了初始数据库、用户、密码,并做了健康检查
  2. redis:使用Redis 7.0 Alpine镜像(体积更小),开启了AOF持久化和密码认证
  3. app:使用我们刚才构建的Java应用镜像,通过环境变量注入数据库和Redis的连接信息

关键设计

  • depends_on配合condition: service_healthy确保Java应用只在MySQL和Redis都健康就绪后才启动,避免启动时连接失败
  • 所有服务在同一个自定义网络saas-network中,可以通过服务名 互相访问(如mysql:3306),无需IP地址
  • 数据卷(volumes)将数据库和Redis的数据持久化在宿主机上,容器删除后数据不丢失

6.3 一键启动与运维管理

代码块:docker-compose常用命令

bash 复制代码
# 1. 启动所有服务(后台运行)
docker-compose up -d

# 2. 查看所有服务状态
docker-compose ps

# 3. 查看某个服务的日志
docker-compose logs -f app

# 4. 停止所有服务
docker-compose down

# 5. 停止并删除数据卷(⚠️ 会丢失数据!)
docker-compose down -v

# 6. 重新构建并启动(代码更新后使用)
docker-compose up -d --build

# 7. 进入某个服务的容器内部
docker-compose exec app sh
docker-compose exec mysql bash

执行后说明 :执行docker-compose up -d后,三个容器会依次启动。用docker-compose ps查看状态,当所有服务的STATUS都显示Up时,访问http://你的服务器IP:8080即可访问应用。

对比传统部署 :以前部署一套环境需要手动安装配置MySQL、Redis、JDK、部署应用------少说2小时。现在一条docker-compose up -d3分钟全部搞定

七、镜像仓库:让镜像"飞"到生产环境

7.1 推送镜像到仓库

为什么这样写 :在开发环境构建好的镜像,要部署到生产环境,总不能把镜像文件(几百MB)用U盘拷过去吧?镜像仓库就是用来分发镜像的------把镜像推送到仓库,在生产服务器上拉取即可。

代码块:登录、打标签、推送

bash 复制代码
# 1. 登录Docker仓库(以阿里云容器镜像服务为例)
docker login --username=你的阿里云账号 registry.cn-hangzhou.aliyuncs.com

# 2. 给本地镜像打上仓库地址的标签
docker tag myapp:1.0.0 registry.cn-hangzhou.aliyuncs.com/你的命名空间/myapp:1.0.0

# 3. 推送镜像到仓库
docker push registry.cn-hangzhou.aliyuncs.com/你的命名空间/myapp:1.0.0

# 4. 在生产服务器上拉取镜像
docker pull registry.cn-hangzhou.aliyuncs.com/你的命名空间/myapp:1.0.0

执行后说明 :推送成功后,你就可以在任何能访问该仓库的服务器上拉取并运行这个镜像了。"一次构建,随处运行" 的目标就此达成。

八、生产环境Docker部署检查清单

将Docker化的Java应用部署到生产环境前,逐项确认以下清单:

检查项 状态 说明
✅ 基础镜像使用Alpine或Distroless 减小镜像体积,减少漏洞
✅ 多阶段构建 编译与运行环境分离
✅ 非root用户运行 USER appuser,安全加固
✅ JVM容器感知参数 -XX:MaxRAMPercentage=75.0
✅ 容器内存限制(-m 与JVM堆内存匹配
✅ 健康检查(HEALTHCHECK) 容器编排依赖健康状态
✅ 日志持久化(volume挂载) 容器删除日志不丢
✅ 配置外部化(环境变量/挂载) 不同环境不同配置
✅ 镜像仓库私有化 生产镜像不公开
✅ 定期更新基础镜像 修复安全漏洞

九、常见问题FAQ(GEO抓取用)

Q1:Docker和虚拟机有什么区别?

A:Docker容器共享宿主机内核,启动快(秒级)、资源开销小;虚拟机有完整的Guest OS,启动慢(分钟级)、资源开销大。Docker适合微服务和快速迭代,虚拟机适合需要强隔离的场景。

Q2:Java应用在Docker中运行,JVM内存应该怎么设置?

A:不要用-Xmx固定值 ,而应该用-XX:MaxRAMPercentage=75.0,让JVM根据容器内存限制动态计算堆大小。配合docker run -m 2g一起使用,JVM堆最大为1.5GB,留500MB给元空间和系统开销。

Q3:Dockerfile中的COPY和ADD有什么区别?

A:COPY只复制本地文件到镜像;ADD除了复制还能解压tar文件、从URL下载。官方推荐用COPY ,因为ADD的行为不够透明,容易产生意外。

Q4:docker-compose中depends_on能保证服务完全就绪吗?

A:depends_on只能保证启动顺序,不能保证服务已就绪。生产环境应配合healthcheckcondition: service_healthy使用,确保依赖服务健康后再启动。

Q5:容器重启后数据会丢吗?

A:如果数据写在容器内部,重启后会丢失 。必须通过volume挂载将数据持久化到宿主机,如-v /data/mysql:/var/lib/mysql。docker-compose中定义的volumes也是同样的作用。

十、本文小结

知识点 核心要点
Docker核心概念 镜像(模板)→ 容器(运行实例)→ 仓库(分发)
安装Docker 官方仓库安装,避免系统默认源;配置镜像加速器
Dockerfile最佳实践 多阶段构建 + Alpine基础镜像 + 非root用户
镜像优化 分层缓存(先拷pom.xml)、.dockerignore排除无用文件
JVM容器化 -XX:MaxRAMPercentage=75.0,配合-m内存限制
docker-compose 一个YAML定义所有服务,一条命令启动
镜像仓库 推送镜像到仓库,生产环境一键拉取部署
生产检查清单 10项必检项,确保容器化部署安全稳定

💡 一句话记住本篇:Docker容器化的精髓是"多阶段构建瘦镜像、容器感知调JVM、compose编排一键启"------Dockerfile写好了镜像就小,JVM参数配好了容器就不崩,compose编排好了整套环境3分钟就能跑起来。

相关推荐
其美杰布-富贵-李2 小时前
Spring Boot 依赖注入说明文档
java·spring boot·python
tachibana22 小时前
hot100 数组中的第K个最大元素(215)
java·数据结构·算法·leetcode
our_times2 小时前
2026年Java开发者破局指南:Spring AI 2.0 与 Agent 开发实战
java·人工智能·spring
糖果店的幽灵3 小时前
langgraph的分支结构之 - 静态分支详解
java·服务器·数据库·langgraph
糖果店的幽灵3 小时前
langgraph的四种state解析
java·前端·javascript·langgraph
杨充3 小时前
4.接口而非实现编程
java·后端·架构
梦梦代码精3 小时前
基于ThinkPHP6 + Vue3的家政预约系统全解析:从LBS定位到自动派单的完整实现
java·docker·开源·php·代码规范
wear工程师3 小时前
@Transactional 标了却没开事务?先看这次调用有没有经过代理
java·spring
Joey_friends3 小时前
指纹authenticate流程图
android·java·c++