升级Java17+SpringBoot3后应用启动失败问题排查
问题描述
将应用从Java8升级到Java17及SpringBoot3后,已将数据仓库接口从PagingAndSortingRepository替换为ListCrudRepository,但启动时抛出BeanCreationException,核心错误为:
Receiver class org.hibernate.envers.internal.entities.RevisionTypeType does not define or inherit an implementation of the resolved method 'abstract int getSqlType()' of interface org.hibernate.usertype.UserType.
相关仓库代码:
@Repository public interface UserRepo extends ListCrudRepository<User, Long> { Optional<User> findByUsername(String username); Optional<User> findByUsernameAndLkpUserType(String username, LkpUserType lkpUserType); Optional<User> findByEmail(String email); Optional<User> findByRid(Long rid); Page<User> findAllByLkpUserType(LkpUserType lkpUserType, Pageable pageable); }
完整堆栈信息:
Error starting ApplicationContext. To display the condition evaluation report re-run your application with 'debug' enabled. 2023-Aug-14 21:58:35 [restartedMain] ERROR o.s.b.SpringApplication - Application run failed org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Receiver class org.hibernate.envers.internal.entities.RevisionTypeType does not define or inherit an implementation of the resolved method 'abstract int getSqlType()' of interface org.hibernate.usertype.UserType. at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1770) ~[spring-beans-6.0.11.jar:6.0.11] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:598) ~[spring-beans-6.0.11.jar:6.0.11] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:520) ~[spring-beans-6.0.11.jar:6.0.11] at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:326) ~[spring-beans-6.0.11.jar:6.0.11] at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-6.0.11.jar:6.0.11] at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:324) ~[spring-beans-6.0.11.jar:6.0.11] at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200) ~[spring-beans-6.0.11.jar:6.0.11] at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1155) ~[spring-context-6.0.11.jar:6.0.11] at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:932) ~[spring-context-6.0.11.jar:6.0.11] at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:608) ~[spring-context-6.0.11.jar:6.0.11] at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146) ~[spring-boot-3.1.2.jar:3.1.2] at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:734) [spring-boot-3.1.2.jar:3.1.2] at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:436) [spring-boot-3.1.2.jar:3.1.2] at org.springframework.boot.SpringApplication.run(SpringApplication.java:312) [spring-boot-3.1.2.jar:3.1.2] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1306) [spring-boot-3.1.2.jar:3.1.2] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1295) [spring-boot-3.1.2.jar:3.1.2] at com.healthcare.thelab.ThelabApplication.main(ThelabApplication.java:21) [classes/:?] at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:?] at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[?:?] at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?] at java.lang.reflect.Method.invoke(Method.java:568) ~[?:?]
解决方案
1. 对齐Hibernate Envers与SpringBoot3的版本
SpringBoot3.x默认依赖Hibernate6.x,Hibernate Envers作为Hibernate的子模块,必须确保版本完全一致。不要手动指定Envers版本,直接依赖SpringBoot提供的starter:
Maven示例:
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.1.2</version> <!-- 与你的SpringBoot版本一致 --> <relativePath/> </parent> <dependencies> <!-- 引入SpringBoot JPA starter,自动管理Hibernate版本 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <!-- 引入Hibernate Envers,版本由parent自动控制 --> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-envers</artifactId> </dependency> </dependencies>
Gradle示例:
plugins { id 'org.springframework.boot' version '3.1.2' id 'io.spring.dependency-management' version '1.1.2' id 'java' } dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.hibernate:hibernate-envers' }
2. 排查并排除依赖冲突
执行依赖树命令,检查是否有旧版本的Hibernate/Envers被引入:
- Maven:
mvn dependency:tree - Gradle:
./gradlew dependencies
找到冲突的旧版本依赖(比如Hibernate5.x),在对应的依赖中排除:
Maven排除示例:
<dependency> <groupId>第三方依赖groupId</groupId> <artifactId>第三方依赖artifactId</artifactId> <exclusions> <exclusion> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> </exclusion> <exclusion> <groupId>org.hibernate</groupId> <artifactId>hibernate-envers</artifactId> </exclusion> </exclusions> </dependency>
3. 清理构建缓存
清理Maven/Gradle缓存,确保依赖重新下载:
- Maven:
mvn clean install -U - Gradle:
./gradlew clean build --refresh-dependencies
原因分析
Hibernate6.x对org.hibernate.usertype.UserType接口进行了升级,新增了getSqlType()抽象方法。而旧版本的Hibernate Envers(比如5.x)中的RevisionTypeType类并未实现该方法,当SpringBoot3加载Hibernate6.x核心包,但Envers还是旧版本时,就会出现这种方法未找到的错误,本质是依赖版本不兼容导致的接口实现缺失。
内容的提问来源于stack exchange,提问作者Mohammed Ayyad

