集成spring-boot-devtools后Spring Boot应用反射赋值失败求助
我之前也踩过这个坑!问题的核心根源是Spring Boot DevTools的双类加载器机制:它会把咱们自己写的应用代码放到RestartClassLoader里加载,而Hibernate这类第三方库则用LaunchedURLClassLoader加载。当Hibernate通过反射给Student的doc字段赋值时,StudentDoc是由重启类加载器加载的,但Hibernate内部拿到的类型实例可能来自另一个类加载器,这就导致了类型不匹配,直接触发IllegalArgumentException。
下面给你几个可行的解决办法,按优先级排序:
1. 把自定义类型加入DevTools重启白名单
这是最推荐的方案,既能保留DevTools的热重启功能,又能解决类加载器冲突。修改src/main/resources/application.properties,把自定义JSONB类型相关的包/类添加到重启白名单:
# 把自定义类型所在的包加入白名单,让DevTools用同一个类加载器加载 spring.devtools.restart.additional-paths=src/main/java/com/gpch/sample/data/jsonb # 确保不排除这些路径 spring.devtools.restart.exclude=
如果想更精准,也可以直接指定类:
spring.devtools.restart.additional-classpath=com.gpch.sample.data.jsonb.StudentDoc,com.gpch.sample.data.jsonb.JsonBUserType
2. 临时禁用DevTools的重启功能(仅用于验证)
如果你只是想快速确认是不是类加载器的问题,可以先关掉DevTools的重启机制,在配置文件里加:
spring.devtools.restart.enabled=false
不过这样就失去了热重启的便利,所以只建议用来排查问题,不适合长期使用。
3. 调整自定义UserType的类加载逻辑
检查你的JsonBUserType实现,确保在反序列化JSON到StudentDoc时,使用当前线程的上下文类加载器,而不是默认的类加载器。比如在nullSafeGet方法里做这样的调整:
// 在JsonBUserType的nullSafeGet方法中添加类加载器指定 ObjectMapper objectMapper = new ObjectMapper(); // 使用当前线程上下文的类加载器,保证和实体类的类加载器一致 objectMapper.setClassLoader(Thread.currentThread().getContextClassLoader()); return objectMapper.readValue(jsonString, targetClass);
这样反序列化出来的StudentDoc实例就和Student类属于同一个类加载器了,反射赋值自然就不会报错。
4. 升级Spring Boot版本
如果你用的是比较老的Spring Boot版本,不妨试试升级到最新的稳定版——DevTools和Hibernate集成的一些小bug,在新版本里已经被修复了,说不定升级后问题直接就消失了。
内容的提问来源于stack exchange,提问作者Gustavo Ponce

