You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 00:08:13