Spring Boot3.0+Tomcat10升级中Hibernate集成类转换异常求助
Spring Boot 3.0 + Tomcat 10 升级中的Hibernate事件监听器注册异常问题
我正在从Spring Boot 2.7升级到3.0,搭配Tomcat 10使用。遇到了两个类转换异常,虽然猜测是类路径重复JAR,但确认只引入了6.1.7.Final版本的hibernate-core。
方案一:实现Integrator接口配置集成器
异常堆栈
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: class com.model.service.configuration.HibernateEventRegistry cannot be cast to class org.hibernate.jpa.boot.spi.IntegratorProvider (com.model.service.configuration.HibernateEventRegistry and org.hibernate.jpa.boot.spi.IntegratorProvider are in unnamed module of loader org.apache.catalina.loader.ParallelWebappClassLoader @4339e0de) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1762) ~[spring-beans-6.0.6.jar:6.0.6] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:599) ~[spring-beans-6.0.6.jar:6.0.6] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:521) ~[spring-beans-6.0.6.jar:6.0.6] at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:326) ~[spring-beans-6.0.6.jar:6.0.6] at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-6.0.6.jar:6.0.6] at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:324) ~[spring-beans-6.0.6.jar:6.0.6] at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200) ~[spring-beans-6.0.6.jar:6.0.6]
实现代码
package com.model.service.configuration; import org.apache.logging.log4j.Logger; import org.hibernate.boot.Metadata; import org.hibernate.boot.spi.BootstrapContext; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.event.service.spi.EventListenerRegistry; import org.hibernate.integrator.spi.Integrator; import org.hibernate.service.spi.SessionFactoryServiceRegistry; public class HibernateEventRegistry implements Integrator { private static Logger logger = org.apache.logging.log4j.LogManager.getLogger(HibernateEventRegistry.class.getName()); public static final HibernatePersistenceListener persistenceListener = new HibernatePersistenceListener(); @Override public void integrate(Metadata metadata, BootstrapContext bootstrapContext, SessionFactoryImplementor sessionFactory) { logger.info("Registering hibernate event listeners..."); final EventListenerRegistry eventRegistry = sessionFactory.getServiceRegistry().getService(EventListenerRegistry.class); eventRegistry.prependListeners(EventType.POST_COMMIT_INSERT, persistenceListener); eventRegistry.prependListeners(EventType.POST_COMMIT_DELETE, persistenceListener); eventRegistry.prependListeners(EventType.POST_COMMIT_UPDATE, persistenceListener); eventRegistry.prependListeners(EventType.POST_COLLECTION_UPDATE, persistenceListener); eventRegistry.prependListeners(EventType.PRE_COLLECTION_UPDATE, persistenceListener); logger.info("Hibernate event listeners registered"); } @Override public void disintegrate(SessionFactoryImplementor sessionFactory, SessionFactoryServiceRegistry serviceRegistry) { } }
配置方式
在application.properties中添加:
spring.jpa.properties.hibernate.integrator_provider=com.model.service.configuration.HibernateEventRegistry
方案二:通过Spring Service获取SessionFactory注册监听器
该方案在Spring Boot 2.7 + Hibernate 5 + Tomcat 8 + Java 11环境下正常工作,但升级后报错。
异常堆栈
Caused by: java.lang.ClassCastException: class jdk.proxy4.$Proxy288 cannot be cast to class org.hibernate.internal.SessionFactoryImpl (jdk.proxy4.$Proxy288 is in module jdk.proxy4 of loader org.apache.catalina.loader.ParallelWebappClassLoader @c2e3264; org.hibernate.internal.SessionFactoryImpl is in unnamed module of loader org.apache.catalina.loader.ParallelWebappClassLoader @c2e3264) at com.model.service.configuration.HibernateEventRegistry.registerListeners(HibernateEventRegistry.java:35) ~[?:?] 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) ~[?:?] at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleElement.invoke(InitDestroyAnnotationBeanPostProcessor.java:424) ~[?:?] at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleMetadata.invokeInitMethods(InitDestroyAnnotationBeanPostProcessor.java:368) ~[?:?] at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:192) ~[?:?] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(AbstractAutowireCapableBeanFactory.java:420) ~[?:?] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1754) ~[?:?] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:599) ~[?:?] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:521) ~[?:?] at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:326) ~[?:?] at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[?:?] at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:324) ~[?:?] at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200) ~[?:?]
实现代码
package com.model.service.configuration; import jakarta.annotation.PostConstruct; import jakarta.persistence.EntityManagerFactory; import org.apache.logging.log4j.Logger; import org.hibernate.SessionFactory; import org.hibernate.event.service.spi.EventListenerRegistry; import org.hibernate.event.spi.EventType; import org.hibernate.internal.SessionFactoryImpl; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service public class HibernateEventRegistry { private static Logger logger = org.apache.logging.log4j.LogManager.getLogger(HibernateEventRegistry.class.getName()); @Autowired private EntityManagerFactory entityManagerFactory; @Autowired private HibernatePersistenceListener persistenceListener; @PostConstruct public void registerListeners() { logger.info("Registering hibernate event listeners..."); EventListenerRegistry eventRegistry = ((SessionFactoryImpl) entityManagerFactory.unwrap(SessionFactory.class)).getServiceRegistry() .getService(EventListenerRegistry.class); eventRegistry.prependListeners(EventType.POST_COMMIT_INSERT, persistenceListener); eventRegistry.prependListeners(EventType.POST_COMMIT_DELETE, persistenceListener); eventRegistry.prependListeners(EventType.POST_COMMIT_UPDATE, persistenceListener); eventRegistry.prependListeners(EventType.POST_COLLECTION_UPDATE, persistenceListener); eventRegistry.prependListeners(EventType.PRE_COLLECTION_UPDATE, persistenceListener); logger.info("Hibernate event listeners registered"); } }
解决思路
针对方案一的问题
hibernate.integrator_provider配置项要求的是实现org.hibernate.jpa.boot.spi.IntegratorProvider接口的类,而非直接实现Integrator接口的类。需要创建一个实现IntegratorProvider的类,返回你的HibernateEventRegistry实例:
public class CustomIntegratorProvider implements IntegratorProvider { @Override public List<Integrator> getIntegrators() { return Collections.singletonList(new HibernateEventRegistry()); } }
修改application.properties配置:
spring.jpa.properties.hibernate.integrator_provider=com.model.service.configuration.CustomIntegratorProvider
针对方案二的问题
Spring Boot 3.0中,EntityManagerFactory返回的SessionFactory被Spring代理,无法直接强转为SessionFactoryImpl(内部实现类)。正确做法是unwrap到Hibernate的公开SPI接口SessionFactoryImplementor:
SessionFactoryImplementor sessionFactory = entityManagerFactory.unwrap(SessionFactoryImplementor.class); EventListenerRegistry eventRegistry = sessionFactory.getServiceRegistry().getService(EventListenerRegistry.class);
依赖公开SPI接口而非内部实现类,可避免代理导致的转换异常。
额外排查点
- 检查Tomcat的lib目录是否存在遗留的Hibernate相关JAR,避免和项目依赖冲突
- 使用
mvn dependency:tree(Maven)或gradle dependencies(Gradle)确认是否有间接依赖的旧版Hibernate组件 - 确认项目中所有JPA相关导入都来自
jakarta.persistence包,而非旧的javax.persistence包(Spring Boot 3.0基于Jakarta EE 9,API包名变更)
内容的提问来源于stack exchange,提问作者user2028936
相关产品推荐
相关产品推荐

