【问题标题】:Spring hibernate configuration riddleSpring休眠配置之谜
【发布时间】:2021-12-17 23:26:37
【问题描述】:

我现在正在研究 Spring 和 Hibernate,我遇到了一个我找不到解决方案的谜语。它是关于配置 Hibernate 以与 Spring 一起使用。这是 Spring 文档中的 Spring beans xml 配置示例:

<bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
    <property name="dataSource" ref="dataSource"/>
    <property name="mappingResources">
        <list>
            <value>org/springframework/samples/petclinic/hibernate/petclinic.hbm.xml</value>
        </list>
    </property>
    <property name="hibernateProperties">
        <value>
            hibernate.dialect=${hibernate.dialect}
        </value>
    </property>
</bean>

<bean id="txManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory"/>
</bean>

这里可以看到,txManager bean 的 sessionFactory 依赖(我假设的 SessionFactory 类型)被 sessionFactory bean 覆盖,它实际上是 LocalSessionFactoryBean 类。但关键是 LocalSessionFactoryBean 没有实现 SessionFactory,因此它不能用于注入该依赖项。可以从LocalSessionFactoryBean接收SessionFactory,但是需要调用它的getObject方法,这里不做。

这是我项目中的一个示例,但这次使用的是 java 配置:

package com.luv2code.springdemo.config;

import java.beans.PropertyVetoException;
import java.util.Properties;
import java.util.logging.Logger;

import javax.sql.DataSource;

import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.orm.hibernate5.HibernateTransactionManager;
import org.springframework.orm.hibernate5.LocalSessionFactoryBean;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.view.InternalResourceViewResolver;

import com.mchange.v2.c3p0.ComboPooledDataSource;

@Configuration
@EnableWebMvc
@EnableTransactionManagement
@ComponentScan("com.luv2code.springdemo")
@PropertySource({ "classpath:persistence-mysql.properties" })
public class DemoAppConfig implements WebMvcConfigurer {

    @Autowired
    private Environment env;
    
    private Logger logger = Logger.getLogger(getClass().getName());
    
    // define a bean for ViewResolver

    @Bean
    public DataSource myDataSource() {
        
        // create connection pool
        ComboPooledDataSource myDataSource = new ComboPooledDataSource();

        // set the jdbc driver
        try {
            myDataSource.setDriverClass("com.mysql.jdbc.Driver");       
        }
        catch (PropertyVetoException exc) {
            throw new RuntimeException(exc);
        }
        
        // for sanity's sake, let's log url and user ... just to make sure we are reading the data
        logger.info("jdbc.url=" + env.getProperty("jdbc.url"));
        logger.info("jdbc.user=" + env.getProperty("jdbc.user"));
        
        // set database connection props
        myDataSource.setJdbcUrl(env.getProperty("jdbc.url"));
        myDataSource.setUser(env.getProperty("jdbc.user"));
        myDataSource.setPassword(env.getProperty("jdbc.password"));
        
        // set connection pool props
        myDataSource.setInitialPoolSize(getIntProperty("connection.pool.initialPoolSize"));
        myDataSource.setMinPoolSize(getIntProperty("connection.pool.minPoolSize"));
        myDataSource.setMaxPoolSize(getIntProperty("connection.pool.maxPoolSize"));     
        myDataSource.setMaxIdleTime(getIntProperty("connection.pool.maxIdleTime"));

        return myDataSource;
    }
    
    private Properties getHibernateProperties() {

        // set hibernate properties
        Properties props = new Properties();

        props.setProperty("hibernate.dialect", env.getProperty("hibernate.dialect"));
        props.setProperty("hibernate.show_sql", env.getProperty("hibernate.show_sql"));
        
        return props;               
    }

    
    // need a helper method 
    // read environment property and convert to int
    
    private int getIntProperty(String propName) {
        
        String propVal = env.getProperty(propName);
        
        // now convert to int
        int intPropVal = Integer.parseInt(propVal);
        
        return intPropVal;
    }   
    
    @Bean
    public LocalSessionFactoryBean sessionFactory(){
        
        // create session factorys
        LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
        
        // set the properties
        sessionFactory.setDataSource(myDataSource());
        sessionFactory.setPackagesToScan(env.getProperty("hibernate.packagesToScan"));
        sessionFactory.setHibernateProperties(getHibernateProperties());
        
        return sessionFactory;
    }
    
    @Bean
    @Autowired
    public HibernateTransactionManager transactionManager(SessionFactory sessionFactory) {
        
        // setup transaction manager based on session factory
        HibernateTransactionManager txManager = new HibernateTransactionManager();
        txManager.setSessionFactory(sessionFactory);

        return txManager;
    }   
    
}

如您所见,SessionFactory 类型的 transactionManager 方法的参数是由 sessionFactory bean 自动装配的(这很奇怪,但现在不是重点),它又是 LocalSessionFactoryBean 类,它没有实现 SessionFactory 接口,所以我们遇到了和xml配置一样的问题。

我在互联网上的几个地方都看到过这样的例子,所以我想知道它是如何工作的。

【问题讨论】:

    标签: java spring hibernate configuration


    【解决方案1】:

    终于明白了。文档here 指出:

    Spring 容器识别 LocalSessionFactoryBean 实现 FactoryBean 接口,从而处理这个 bean 特别是:LocalSessionFactoryBean 的一个实例被实例化,但是 而不是直接返回,而是 getObject() 方法是 调用。从这个调用 getObject() 返回的对象是 最终注册为 sessionFactory bean。

    【讨论】:

      猜你喜欢
      • 2018-12-16
      • 2014-11-05
      • 2016-11-06
      • 2011-05-03
      • 1970-01-01
      • 2010-11-08
      • 2016-01-19
      • 1970-01-01
      • 2015-07-28
      相关资源
      最近更新 更多