SpringBoot自定义JSON序列化/反序列化在GitLab CI/CD部署Docker时失效,Jenkins正常
SpringBoot自定义Jackson序列化逻辑失效故障排查
项目基础上下文
- 框架版本:
SpringBoot 2.3.1.RELEASE - 核心Gradle依赖配置:
dependencies { implementation 'org.springframework.boot:spring-boot-starter-actuator' implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.boot:spring-boot-starter-tomcat' }
- 技术栈默认规则:引入
spring-boot-starter-web依赖后,项目默认内置Jackson库完成全链路JSON序列化、反序列化处理,前后端交互全量采用JSON格式通信。 - 标准化发布流程:
- 从Git分支拉取最新代码
- 通过Gradle Wrapper完成项目构建
- 基于构建产出的Jar包,通过预置Dockerfile构建应用Docker镜像
- 通过docker-compose.yml启动运行新构建的Docker镜像
故障异常表现
- 触发条件:GitLab CI/CD流水线完成Docker镜像构建、容器正常启动后,自定义的JSON序列化/反序列化逻辑完全不生效
- 具体报错日志:
Exception--------org.springframework.http.converter.HttpMessageNotReadableException org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot deserialize value of type "java.time.LocalDate" from String "20210412": Failed to deserialize java.time.LocalDate: (java.time.format.DateTimeParseException) Text '20210412' could not be parsed at index 0; nested exception is com.fasterxml.jackson.databind.exc.InvalidFormatException: Cannot deserialize value of type "java.time.LocalDate" from String "20210412": Failed to deserialize java.time.LocalDate: (java.time.format.DateTimeParseException) Text '20210412' could not be parsed at index 0
- 反常对比特征:同一台物理服务器上,基于完全相同的代码文件构建,Jenkins流水线与GitLab CI/CD流水线产出的服务运行效果存在明确差异:
- 两流程唯一差异点:代码存放目录不同、构建产出文件属主不同(Jenkins流程文件属主为
root:root,GitLab CI/CD流程相关文件属主为gitlab-runner:gitlab-runner) - 两流程完全一致的配置:使用同一份Dockerfile、同一份docker-compose.yml配置,Docker镜像构建、服务启动流程均能正常完成,无构建报错、启动报错
- 故障排他性:仅GitLab CI/CD流水线产出的服务实例存在自定义JSON序列化/反序列化失效问题,Jenkins流水线产出的同版本服务运行完全正常
- 核心矛盾点:两流程使用完全一致的代码、Docker配置、运行环境,仅构建执行的系统用户、文件目录属主存在差异,最终服务运行效果却存在本质区别
- 两流程唯一差异点:代码存放目录不同、构建产出文件属主不同(Jenkins流程文件属主为
根因排查方向
- 构建环节差异校验
- 逐包对比两个流水线产出的Jar包内容:检查
BOOT-INF/classes路径下,自定义Jackson配置类、针对LocalDate的自定义序列化/反序列化类是否被完整打包,排除Gradle构建缓存差异导致的类遗漏问题——尤其要注意GitLab Runner用户下的本地Gradle缓存是否存在历史遗留的旧版本类文件,在增量构建时没有覆盖最新代码 - 对比两个流程下的Gradle构建输出日志,确认自定义Jackson相关的配置类没有因为编译期注解处理、资源过滤规则的差异,被排除在最终Jar包外
- 逐包对比两个流水线产出的Jar包内容:检查
- 运行时加载差异校验
- 检查GitLab Runner用户工作目录下的外部配置文件加载情况:确认是否存在因为目录权限问题,导致应用没有加载到预置的Jackson格式配置(比如
spring.jackson.date-format、自定义序列化注册项) - 对比两个服务实例启动时的类加载顺序,确认是否存在类加载优先级偏移:比如GitLab Runner环境下,类加载器优先加载了Jackson内置的默认
LocalDate反序列化实现,跳过了自定义的序列化逻辑注册
- 检查GitLab Runner用户工作目录下的外部配置文件加载情况:确认是否存在因为目录权限问题,导致应用没有加载到预置的Jackson格式配置(比如
- 隐性权限影响校验
- 检查GitLab Runner运行上下文下,应用是否有权限读取Jar包内
META-INF路径下的Jackson SPI扩展注册文件(比如Jackson2ObjectMapperBuilderCustomizer的SPI配置),排除权限不足导致的自定义扩展加载被跳过的问题
- 检查GitLab Runner运行上下文下,应用是否有权限读取Jar包内
内容的提问来源于stack exchange,提问作者Inhwa Son
相关产品推荐
相关产品推荐

