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

Spring+Hibernate中postProcessAfterInitialization初始化SessionFactory为何被调用两次?

Spring+Hibernate中SessionFactory触发BeanPostProcessor两次的问题

在基于注解配置的Spring与Hibernate环境中,我发现postProcessAfterInitialization方法在创建SessionFactory时被调用了两次,但其他Bean的该方法仅被调用一次。以下是我的配置代码:

package org.example.excel.Configuration;

import org.example.excel.ClassFactory.ClassBuilderFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.hibernate5.HibernateTransactionManager;
import org.springframework.orm.hibernate5.LocalSessionFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
import javax.sql.DataSource;
import java.util.Properties;

@Configuration
public class HibernateConfig implements BeanPostProcessor {

    private ClassBuilderFactory classBuilderFactory;

    @Autowired
    public HibernateConfig(ClassBuilderFactory classBuilderFactory) {
        this.classBuilderFactory = classBuilderFactory;
    }

    @Bean
    public LocalSessionFactoryBean sessionFactoryBean() {
        LocalSessionFactoryBean sessionFactoryBean = new LocalSessionFactoryBean();
        sessionFactoryBean.setDataSource(dataSource());
        sessionFactoryBean.setHibernateProperties(hibernateProperties());
        sessionFactoryBean.setPackagesToScan("org.example.excel.Model");
        return sessionFactoryBean;
    }

    @Bean
    public DataSource dataSource() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName("oracle.jdbc.OracleDriver");
        dataSource.setUrl("jdbc:oracle:thin:@localhost:1521:xe");
        dataSource.setUsername("Test");
        dataSource.setPassword("1234");
        return dataSource;
    }

    public Properties hibernateProperties() {
        Properties properties = new Properties();
        properties.setProperty("hibernate.dialect", "org.hibernate.dialect.Oracle10gDialect");
        properties.setProperty("hibernate.hbm2ddl.auto", "update");
        properties.setProperty("hibernate.current_session_context_class", "org.hibernate.context.internal.JTASessionContext");
        properties.setProperty("hibernate.show_sql", "true");
        return properties;
    }

    @Bean
    public PlatformTransactionManager hibernateTransactionManager() {
        HibernateTransactionManager tr = new HibernateTransactionManager();
        tr.setSessionFactory(sessionFactoryBean().getObject());
        return tr;
    }
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("in before" + beanName);
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("in after " + beanName);
        return bean;

    }
}

问题原因

问题核心出在hibernateTransactionManager()方法里的sessionFactoryBean().getObject()调用:

  • 虽然Spring的@Configuration类默认会被代理,正常调用内部@Bean方法会返回容器单例,但你的HibernateConfig同时实现了BeanPostProcessor,在容器初始化BeanPostProcessor的阶段,代理逻辑还未完全生效。
  • 直接调用sessionFactoryBean()会手动创建一个新的LocalSessionFactoryBean实例,加上Spring容器本身初始化的实例,就产生了两个LocalSessionFactoryBean对象。这两个对象都会被你的BeanPostProcessor处理,因此postProcessAfterInitialization会被触发两次。

解决方法

方法一:注入LocalSessionFactoryBean

修改事务管理器的Bean定义,通过依赖注入获取容器中的LocalSessionFactoryBean实例,避免手动创建新对象:

@Bean
public PlatformTransactionManager hibernateTransactionManager(@Autowired LocalSessionFactoryBean sessionFactoryBean) {
    HibernateTransactionManager tr = new HibernateTransactionManager();
    tr.setSessionFactory(sessionFactoryBean.getObject());
    return tr;
}

方法二:直接注入SessionFactory

LocalSessionFactoryBean是Spring的FactoryBean,它会自动将生成的SessionFactory作为Bean暴露在容器中,因此可以直接注入SessionFactory类型:

@Bean
public PlatformTransactionManager hibernateTransactionManager(@Autowired SessionFactory sessionFactory) {
    HibernateTransactionManager tr = new HibernateTransactionManager();
    tr.setSessionFactory(sessionFactory);
    return tr;
}

两种方式都能确保仅使用容器中的单例LocalSessionFactoryBean实例,从而消除BeanPostProcessor重复调用的问题。

内容的提问来源于stack exchange,提问作者mehdi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 01:40:34