Spring Boot + Docker:实现可挂载可热更新的 config.json

文章目录

前言:在实际项目中,我们经常需要让前端读取一个 config.json,并且希望它 支持在 Docker 容器里挂载覆盖、实时生效 ,避免每次修改都要重新打包。


一、背景:为什么 jar 内的 config.json 不能被覆盖?

很多人遇到这样的场景:

  • 前端请求 GET /config.json
  • 想通过 Docker 挂载一份外部 config.json 到容器里覆盖 jar 里的那份
  • 结果发现改了也不生效 → 还是读到打包进 jar 的老版本

🔎 根本原因:

Spring Boot 不会自动替换 jar 内部的静态资源文件,挂载的静态资源只是在查找路径里排在前面而已。

换句话说:

文件如果在 jar 里,通过 classpath 加载的优先级并不因为挂载而被覆盖(实际查找路径可能不同)。


二、Spring Boot 静态资源加载机制

在 Spring Boot 里,静态资源是这样被查找的:

properties 复制代码
# Spring Boot 2.4+ 使用这个
spring.web.resources.static-locations=file:/app/static/, classpath:/static/

# Spring Boot 2.3- 使用这个
spring.resources.static-locations=file:/app/static/, classpath:/static/

这个配置表示:

优先级 资源位置
第一 外部目录 file:/app/static/
第二 jar 内 classpath:/static/

注意:这是查找顺序,不是覆盖机制。


三、解决方案结构

为了做到:

✔ Docker 容器挂载的 config.json 可覆盖

✔ 修改后立即生效(无重启,无缓存)

✔ 支持 /config.json 和 /wvp/config.json 两种访问路径

我们的整体方案是:

复制代码
前端请求 /config.json 或 /wvp/config.json
→ 后端 Controller 先尝试读取 容器内 /app/config/config.json
→ 如果存在直接返回
→ 如果不存在再 fallback 到 classpath:/static/config.json

同时设置返回头 Cache-Control: no-store 避免浏览器缓存旧配置。


四、核心实现:优先读外部文件

在你的 Controller 里写如下逻辑:

java 复制代码
@RestController
public class WvpIndexController {

    private static final String EXTERNAL_PATH = "/app/config/config.json";
    private static final String CLASSPATH_PATH = "classpath:/static/config.json";

    @GetMapping({"/config.json", "/wvp/config.json"})
    public ResponseEntity<Resource> getConfig(HttpServletResponse response) {

        Resource resource;

        // 1) 优先尝试读取外部挂载文件
        File external = new File(EXTERNAL_PATH);
        if (external.exists() && external.isFile()) {
            resource = new FileSystemResource(external);
        } else {
            // 2) 不存在则 fallback 到内置 classpath
            resource = new ClassPathResource("static/config.json");
        }

        // 设置不缓存
        response.setHeader("Cache-Control", "no-store");

        return ResponseEntity.ok()
                .contentType(MediaType.APPLICATION_JSON)
                .body(resource);
    }
}

五、完整 Dockerfile 示例

dockerfile 复制代码
FROM openjdk:17-jdk-alpine

WORKDIR /app

COPY wvp.jar /app/wvp.jar
COPY static /app/static  # 静态资源 fallback

EXPOSE 8080

ENTRYPOINT ["java", \
  "-Dspring.web.resources.static-locations=file:/app/static/,classpath:/static/", \
  "-Dspring.resources.static-locations=file:/app/static/,classpath:/static/", \
  "-jar", "wvp.jar"]

八、总结

方案 是否可挂载覆盖 是否热更新 是否兼容多个路径
只依赖 Spring Boot 静态资源 ❌ ❌ ❌
加上后端优先逻辑 ✅ ✅ ✅

✨ 推荐方案:后端优先读取外部挂载文件 + fallback classpath + no-cache

这样你只要:

bash 复制代码
docker-compose up -d

然后在宿主机改 config.json,前端刷新立即生效 💪

相关推荐
譕痕3 天前
JSONObject与JSONArray封装数据格式区别
java·json
A黄俊辉A3 天前
uniapp webview中实现 app和内嵌的H5双向通信
vue.js·json
分布式存储与RustFS3 天前
MinIO 官方 Docker 镜像被移除:依赖它的项目该怎么办
docker·云原生·devops·对象存储·minio·分布式存储
vipxieliang3 天前
ValidX 在 DDD 领域驱动设计中的实践
java·spring boot
kybs19913 天前
全球灾害数据分析可视化 毕业设计-附源码66794
vue.js·spring boot·mysql·安全·django·c#·asp.net
玉&心3 天前
通过Arthas在线诊断K8S中的内存及JVM等使用情况
docker·k8s·arthas
xing-xing3 天前
Docker容器中Nginx站点根目录网页配置访问
nginx·docker
guo_wen_qiang3 天前
上传本地镜像到harbor中
docker·容器·持续部署
羑悻的小杀马特3 天前
Dockerfile 全景指南:从入门编写dockerfile到生产环境镜像优化实战,一步步带你从啃透制作指令到镜像制作落地!
docker·dockerfile·镜像制作
BianHuanShiZhe3 天前
docker常见命令
docker