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
相关产品推荐
相关产品推荐

