Spring+Hibernate CRUD API遇同类ClassCastException异常求助
问题场景
开发Spring Boot + Hibernate的CRUD API时,直接调用DAO的read方法能正常获取User对象,但通过Spring Controller调用时抛出ClassCastException,异常提示同一个models.User类被两个不同类加载器加载:系统类加载器('app'模块)和Spring Boot DevTools的RestartClassLoader。
核心原因
Spring Boot DevTools的热重启功能会用独立类加载器加载应用代码,若Hibernate的SessionFactory是在DevTools类加载器初始化前(比如静态工具类初始化)创建的,就会使用系统类加载器加载实体类。当Controller通过DevTools类加载器调用DAO时,Hibernate返回的User对象是系统类加载器实例,而方法返回类型是DevTools类加载器加载的User类型,导致类型转换失败。
解决方法
1. 将SessionFactory交给Spring容器管理
放弃静态工具类HibernateSessionFactoryUtil手动创建SessionFactory,让Spring统一管理,确保它使用DevTools类加载器初始化:
Hibernate配置类
@Configuration public class HibernateConfig { @Bean public SessionFactory sessionFactory() { LocalSessionFactoryBean sessionFactoryBean = new LocalSessionFactoryBean(); sessionFactoryBean.setDataSource(dataSource()); sessionFactoryBean.setPackagesToScan("models"); // 实体类所在包 sessionFactoryBean.setHibernateProperties(hibernateProperties()); sessionFactoryBean.afterPropertiesSet(); return sessionFactoryBean.getObject(); } @Bean public DataSource dataSource() { HikariDataSource dataSource = new HikariDataSource(); dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/your_db"); dataSource.setUsername("db_user"); dataSource.setPassword("db_password"); return dataSource; } private Properties hibernateProperties() { Properties props = new Properties(); props.put("hibernate.dialect", "org.hibernate.dialect.MySQL8Dialect"); props.put("hibernate.show_sql", "true"); props.put("hibernate.hbm2ddl.auto", "update"); return props; } }
修改UserDAO,注入SessionFactory
@Repository public class UserDAO { private final SessionFactory sessionFactory; // 构造函数注入 public UserDAO(SessionFactory sessionFactory) { this.sessionFactory = sessionFactory; } public User read(int id) { Transaction transaction = null; User user = null; try (Session session = sessionFactory.openSession()) { transaction = session.beginTransaction(); user = session.get(User.class, id); transaction.commit(); } catch (Exception e) { if (transaction != null) transaction.rollback(); e.printStackTrace(); } return user; } }
2. 调整DevTools类加载排除规则(保留手动创建SessionFactory时用)
在src/main/resources/META-INF/spring-devtools.properties中添加配置,确保Hibernate核心包和实体类被DevTools类加载器加载:
restart.include.hibernate=/hibernate-core-.*\.jar restart.include.models=/your-app-artifact-id-.*\.jar
将your-app-artifact-id替换为你的Maven/Gradle项目的artifactId。
3. 清理项目缓存
执行以下操作彻底清除缓存:
- 停止应用,执行
mvn clean(Maven)或gradle clean(Gradle) - 删除IDE缓存目录(比如IntelliJ的
.idea文件夹、Eclipse的.metadata) - 重新构建并启动应用
验证
修改完成后,调用/users/{id}接口,应能正常返回User对象,不再抛出ClassCastException。
内容的提问来源于stack exchange,提问作者Captain_Alekor

