Spring 4 + Hibernate 4:使用LocalSessionFactoryBean和SessionFactory的ClassCastException

时间:2014-04-08 16:50:41

标签: spring hibernate spring-data sessionfactory

通过Spring库,我必须以jar库的形式开发一个DAL(数据访问层),它将被导入到主应用程序中。 我想使用Hibernate访问MySQL数据库和DBCP来管理连接池。

我编写了配置文件DALConfig.java,其中包含DAL bean的配置:

package my.dal.config;

import java.util.Properties;
import javax.annotation.Resource;
import org.apache.commons.dbcp2.BasicDataSource;
import org.apache.commons.dbcp2.BasicDataSourceFactory;
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.dao.annotation.PersistenceExceptionTranslationPostProcessor;
import org.springframework.orm.hibernate4.HibernateTransactionManager;

// Needed by Spring to add this class to the ApplicationContext's configuration
@Configuration
@ComponentScan(basePackages = { "my.dal.config" })
// Property file in which are written the MySQL connection properties
@PropertySource("classpath:dbconnection.properties")

public class DALConfig {

    private static final String PROPERTY_NAME_DATABASE_DRIVER = "db.driver";  
    private static final String PROPERTY_NAME_DATABASE_PASSWORD = "db.password";  
    private static final String PROPERTY_NAME_DATABASE_URL = "db.url";  
    private static final String PROPERTY_NAME_DATABASE_USERNAME = "db.username";  
    private static final String PROPERTY_NAME_POOL_INITIAL_SIZE = "pool.initialsize";
    private static final String PROPERTY_NAME_POOL_MAX_IDLE = "pool.maxidle";

    // Needed to access property file
    @Resource
    private Environment environment;

    // The bean which defines the BasicDataSource (DBCP)
    @Bean
    public BasicDataSource dataSource() throws Exception
    {
        Properties props = new Properties();
        props.put("driverClassName", environment.getProperty(PROPERTY_NAME_DATABASE_DRIVER));
        props.put("url", environment.getProperty(PROPERTY_NAME_DATABASE_URL));
        props.put("username", environment.getProperty(PROPERTY_NAME_DATABASE_USERNAME));
        props.put("password", environment.getProperty(PROPERTY_NAME_DATABASE_PASSWORD));
        props.put("initialSize", environment.getProperty(PROPERTY_NAME_POOL_INITIAL_SIZE));
        props.put("maxIdle", environment.getProperty(PROPERTY_NAME_POOL_MAX_IDLE));

        BasicDataSource bds = BasicDataSourceFactory.createDataSource(props);

        return bds;

    }

    // Bean used to translate Hibernate's exceptions into Spring's ones
    @Bean
    public PersistenceExceptionTranslationPostProcessor persistenceExceptionTranslationPostProcessor()
    {
        PersistenceExceptionTranslationPostProcessor b = new PersistenceExceptionTranslationPostProcessor();
        return b;
    }
}

然后我编写了包含Hibernate配置内容的HibernateConfig.java配置文件

package my.dal.hibernateconfig;

import java.util.Properties;
import javax.annotation.Resource;
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.hibernate4.HibernateTransactionManager;
import org.springframework.orm.hibernate4.LocalSessionFactoryBean;


@Configuration
@ComponentScan(basePackages = { "my.dal.hibernatesessionfactory" })
@PropertySource("classpath:dbconnection.properties")
public class HibernateConfig {

    private static final String PROPERTY_NAME_DAL_CLASSES_PACKAGE = "hibernate.dal.package";  
    private static final String PROPERTY_NAME_HIBERNATE_DIALECT = "hibernate.dialect";  

    @Resource
    private Environment environment;  

    @Autowired
    DataSource dataSource;

    // Bean which defines the FactoryBean for the SessionBean
    @Bean
    public LocalSessionFactoryBean sessionFactory()
    {
        LocalSessionFactoryBean lsfb = new LocalSessionFactoryBean();

        lsfb.setPackagesToScan(PROPERTY_NAME_DAL_CLASSES_PACKAGE);

        Properties hibernateProperties = new Properties();
        hibernateProperties.put("dialect", PROPERTY_NAME_HIBERNATE_DIALECT);
        lsfb.setHibernateProperties(hibernateProperties);

        lsfb.setDataSource(dataSource);
        return lsfb;
    }

    @Bean
    public HibernateTransactionManager transactionManager()
    {
        // THE EXCEPTION IS THROWN AT THIS LINE
        HibernateTransactionManager htm = new HibernateTransactionManager((SessionFactory) sessionFactory());
        return htm;
    }
}

接下来,我编写了UserDAO.java类,它是User类的DAO,它为数据库的用户表建模。

package my.dal.dao;

import my.models.User;

import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

@Component
@Repository
@Transactional
public class UserDAO
{
    private SessionFactory sessionFactory;

    @Autowired
    public UserDAO(SessionFactory sessionFactory) {
        this.sessionFactory=sessionFactory;
    }

    public int insert(User user) {
        return (Integer) sessionFactory.getCurrentSession().save(user);
    }

    public User getByUsername(String username) {
        return (User) sessionFactory.getCurrentSession().get(User.class, username);
    }

    public void update(User user) {
        sessionFactory.getCurrentSession().merge(user); // .update(user);
    }

    public void delete(String username) {
        User u = getByUsername(username);
        sessionFactory.getCurrentSession().delete(u);
    }
}

映射类User.java(使用Eclipse' Hibernate工具生成)

package my.models;

public class User implements java.io.Serializable {

    private String username;
    private String idUserKeystone;
    private String firstName;
    private String lastName;
    private String password;
    private String email;
    private String emailRef;
    private String employer;
    private boolean confirmed;

    // Getters, setters and full constructor
}

现在我想测试DAL。测试类为DALTest.java

package my.dal.tests;

import static org.junit.Assert.assertTrue;
import my.dal.config.DALConfig;
import my.dal.dao.UserDAO;
import my.dal.hibernateconfig.HibernateConfig;
import my.models.User;
import org.hibernate.SessionFactory;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@ContextConfiguration(classes = { DALConfig.class, HibernateConfig.class})
@RunWith(SpringJUnit4ClassRunner.class)
public class DALTest {

    @Autowired
    UserDAO userDAO;

    @Test
    public void testGetUser() {
        User user = null;

        // Let's see if the user "myuser" is into the database
        user = userDAO.getByUsername("myuser");

        assertTrue(null != user);
    }

}

当我运行测试时,会抛出以下异常

java.lang.IllegalStateException: Failed to load ApplicationContext
    ...
    Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'transactionManager' defined in class my.dal.hibernateconfig.HibernateConfig: Instantiation of bean failed; nested exception is org.springframework.beans.factory.BeanDefinitionStoreException: Factory method [public org.springframework.orm.hibernate4.HibernateTransactionManager my.dal.hibernateconfig.HibernateConfig.transactionManager()] threw exception; nested exception is java.lang.ClassCastException: org.springframework.orm.hibernate4.LocalSessionFactoryBean$$EnhancerBySpringCGLIB$$d866ed45 cannot be cast to org.hibernate.SessionFactory
    ...
    Caused by: java.lang.ClassCastException: org.springframework.orm.hibernate4.LocalSessionFactoryBean$$EnhancerBySpringCGLIB$$d866ed45 cannot be cast to org.hibernate.SessionFactory
            at my.dal.hibernateconfig.HibernateConfig.transactionManager(HibernateConfig.java:55)
            at my.dal.hibernateconfig.HibernateConfig$$EnhancerBySpringCGLIB$$bd53a036.CGLIB$transactionManager$1(<generated>)
            at my.dal.hibernateconfig.HibernateConfig$$EnhancerBySpringCGLIB$$bd53a036$$FastClassBySpringCGLIB$$119f2c5b.invoke(<generated>)
        ...

似乎问题是线上的演员

HibernateTransactionManager htm = new HibernateTransactionManager((SessionFactory) sessionFactory())

相反,互联网充满了以这种方式写出这一行的例子。

可能是什么问题?

提前谢谢

1 个答案:

答案 0 :(得分:3)

FactoryBean<Foo>是一个创建Foo类型对象的bean。它本身不属于Foo类型(正如javadoc将向您展示的那样)。要获得它创建的Foo,只需在工厂bean上调用getObject()

HibernateTransactionManager htm = 
    new HibernateTransactionManager(sessionFactory().getObject());