Spring6+Hibernate5+Wildfly28启动报错javax/validation/ValidatorFactory问题
环境:Spring 6.1.7、Hibernate 5.6.7.Final、Wildfly 28服务器
web.xml中context-param配置:
<context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/applicationContext-root.xml, /WEB-INF/applicationContext-slis-security.xml, /WEB-INF/applicationContext-slis.xml</param-value> </context-param>
applicationContext-slis.xml中的SessionFactory Bean配置:
<bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <property name="packagesToScan" value="hk.housingauthority.slis.model" /> <property name="configLocation" value="classpath:hibernate.cfg.xml" /> </bean>
启动服务器时核心报错:
Caused by: org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'sessionFactory' defined in
ServletContext resource [/WEB-INF/applicationContext-slis.xml]:
javax/validation/ValidatorFactory at
deployment.SLISEAR-0.0.1-SNAPSHOT.ear.SLIS-0.0.1-SNAPSHOT.war//org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1788)
...(省略部分栈信息)
Caused by: java.lang.NoClassDefFoundError:
javax/validation/ValidatorFactory at
java.base/java.lang.Class.getDeclaredMethods0(Native Method)
...(省略部分栈信息)
疑问
- 该错误是否由
org.springframework.orm.hibernate5.LocalSessionFactoryBean类导致?如何修复? - 查看Spring ORM 5.0.9.RELEASE版本中
LocalSessionFactoryBean的源码,未发现对jakarta.validation.ValidatorFactory的引用,为何报错会提及javax/validation/ValidatorFactory? - Hibernate 6中有说明:“Hibernate ORM 6.x is officially only supported as a JPA provider. Please use LocalContainerEntityManagerFactoryBean with JpaTransactionManager there instead.”,该语句是什么含义?
1. 错误根源与修复方案
错误是否由LocalSessionFactoryBean导致?
不是直接由LocalSessionFactoryBean导致。报错本质是API规范的环境冲突:
- Wildfly 28属于Jakarta EE 10环境,所有Java EE相关API已从
javax.*迁移至jakarta.*包路径; - Hibernate 5.6.7.Final默认依赖旧版Bean Validation(JSR-380)的
javax.validation包,但Wildfly 28的类路径中只有jakarta.validation相关类,不存在javax.validation.ValidatorFactory。当Spring初始化LocalSessionFactoryBean并创建Hibernate SessionFactory时,Hibernate内部触发了该类的加载,最终抛出NoClassDefFoundError。
修复方案
提供两种可行解决路径:
路径一:适配Jakarta环境的Hibernate依赖
将Hibernate 5.6的核心依赖替换为Jakarta兼容版本(Hibernate 5.6提供了Jakarta分支包),示例Maven依赖:
<!-- 替换原hibernate-core依赖 --> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core-jakarta</artifactId> <version>5.6.15.Final</version> </dependency> <!-- 引入Jakarta Validation API --> <dependency> <groupId>jakarta.validation</groupId> <artifactId>jakarta.validation-api</artifactId> <version>3.0.2</version> </dependency>
该方案无需修改现有Spring配置,可继续使用LocalSessionFactoryBean。
路径二:切换为JPA规范集成(长期推荐)
若后续计划升级到Hibernate 6,建议直接切换为Spring JPA集成方式:
- 移除
LocalSessionFactoryBean配置,改用LocalContainerEntityManagerFactoryBean:
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="packagesToScan" value="hk.housingauthority.slis.model"/> <property name="jpaVendorAdapter"> <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/> </property> <property name="jpaProperties"> <props> <!-- 原hibernate.cfg.xml中的配置可迁移至此 --> <prop key="hibernate.hbm2ddl.auto">update</prop> <prop key="hibernate.show_sql">true</prop> </props> </property> </bean>
- 将事务管理器替换为
JpaTransactionManager:
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> <property name="entityManagerFactory" ref="entityManagerFactory"/> </bean>
2. 为何报错提及javax/validation/ValidatorFactory?
你查看的是Spring ORM 5.0.9的源码,但当前使用的是Spring 6.1.7,更关键的是:该类引用并非来自Spring的LocalSessionFactoryBean,而是来自Hibernate内部类。
当Spring调用LocalSessionFactoryBean的afterPropertiesSet()方法创建Hibernate SessionFactory时,Hibernate核心类(如SessionFactoryImpl)会依赖Bean Validation组件做实体校验,而Hibernate 5.6默认绑定的是javax.validation包下的API,因此加载这些Hibernate类时,JVM会尝试寻找javax.validation.ValidatorFactory,但Wildfly 28中只有jakarta.validation版本的类,最终抛出错误。
3. Hibernate 6说明语句的含义
这句话的中文意思是:Hibernate ORM 6.x官方仅支持作为JPA提供者使用,不再支持原生Hibernate SessionFactory的直接创建方式,建议使用LocalContainerEntityManagerFactoryBean配合JpaTransactionManager完成集成。
原因是Hibernate 6完全基于Jakarta EE规范重构,放弃了对原生SessionFactory非JPA模式的官方支持,强制用户通过JPA标准的EntityManagerFactory操作数据库,以此更好兼容Jakarta EE生态,同时统一ORM操作规范。
内容的提问来源于stack exchange,提问作者user1169587

