如何在Docker Compose运行的Maven多模块项目中使用Spring Dev Tools热重载
Spring Boot多模块Maven项目Docker化后无法实现DevTools热重载
项目背景
我有一个Spring Boot、Maven多模块项目,通过Docker Compose运行,项目能正常启动,但Spring Dev Tools热重载功能失效。
项目结构
my-service - api (子模块) - domain (子模块) - entity (子模块) - graphql (主模块) - repository (子模块)
当前Dockerfile配置
FROM openjdk:21-jdk-slim as dependencies WORKDIR /app COPY . . RUN ./mvnw dependency:go-offline FROM dependencies as build RUN ./mvnw package spring-boot:repackage FROM openjdk:21-jdk-slim as runtime COPY --from=build /app/graphql/target/graphql-0.0.1-SNAPSHOT.jar /app/graphql/target/ EXPOSE 8080 CMD ["java", "-jar", "/app/graphql/target/graphql-0.0.1-SNAPSHOT.jar"] FROM openjdk:21-jdk-slim as debug COPY --from=build /app/graphql/target/graphql-0.0.1-SNAPSHOT.jar /app/graphql/target/ EXPOSE 5006 CMD ["java", "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5006", "-jar", "/app/graphql/target/graphql-0.0.1-SNAPSHOT.jar"]
docker-compose.yml配置
version: "3.8" services: my-service: build: context: . target: debug environment: - SPRING_PROFILES_ACTIVE=local volumes: - "~/.m2:/root/.m2" - ".:/app" ports: - "8080:8080" - "5050:5006"
遇到的问题
尝试配置热重载后,启动服务发送GraphQL查询时,持续出现类加载器冲突错误:
my-service-1 | java.lang.ClassCastException: class com.example.myservice.repository.MyClass cannot be cast to class com.example.myservice.repository.MyClass (com.example.myservice.repository.MyClass is in unnamed module of loader 'app'; com.example.myservice.repository.MyClass is in unnamed module of loader org.springframework.boot.devtools.restart.classloader.RestartClassLoader @3bbdbc95)
解决方案
1. 调整Docker镜像,改用spring-boot:run启动而非打包Jar
当前Dockerfile先打包成Jar再运行,DevTools热重载需要实时编译的类文件,而非打包后的Jar。修改Dockerfile的debug阶段:
FROM openjdk:21-jdk-slim as dependencies WORKDIR /app COPY . . RUN ./mvnw dependency:go-offline FROM dependencies as debug EXPOSE 8080 EXPOSE 5006 CMD ["./mvnw", "-pl", "graphql", "spring-boot:run", "-Dspring-boot.run.jvmArguments='-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5006'"]
-pl graphql指定只运行主模块,避免编译所有子模块浪费时间- 直接用
spring-boot:run启动,DevTools可实时监测类文件变化
2. 配置Spring DevTools重启策略
在主模块graphql的src/main/resources/application-local.properties中添加:
# 开启自动重启 spring.devtools.restart.enabled=true # 指定需要监测变化的子模块源码路径 spring.devtools.restart.additional-paths=../api/src/main/java,../domain/src/main/java,../entity/src/main/java,../repository/src/main/java # 排除无需监测的静态资源目录 spring.devtools.restart.exclude=static/**,public/** # 禁用模板缓存,确保资源实时生效 spring.thymeleaf.cache=false spring.freemarker.cache=false
3. 解决类加载器冲突
类转换异常是因为同一个类被两个不同类加载器加载,需确保子模块类被RestartClassLoader统一加载:
在主模块graphql的src/main/resources/META-INF/spring-devtools.properties中添加:
# 指定需要被RestartClassLoader加载的子模块Jar包 restart.include.api=/api-.+\\.jar restart.include.domain=/domain-.+\\.jar restart.include.entity=/entity-.+\\.jar restart.include.repository=/repository-.+\\.jar
4. 调整Docker Compose挂载配置
确保本地代码修改实时同步到容器,同时避免本地无target目录时覆盖容器内编译产物:
version: "3.8" services: my-service: build: context: . target: debug environment: - SPRING_PROFILES_ACTIVE=local - MAVEN_OPTS=-Dspring.devtools.restart.enabled=true volumes: - "~/.m2:/root/.m2" - ".:/app" # 隔离容器内的target目录,避免本地覆盖 - /app/graphql/target - /app/api/target - /app/domain/target - /app/entity/target - /app/repository/target ports: - "8080:8080" - "5050:5006"
5. 验证热重载
启动容器后,修改任意子模块的Java代码,等待容器内Maven自动编译,DevTools会触发应用重启,之后验证接口是否生效。
内容的提问来源于stack exchange,提问作者user3067870
相关产品推荐
相关产品推荐

