【问题标题】:Spring 4 + Hibernate 4 IllegalArgumentException: Property 'sessionFactory' is requiredSpring 4 + Hibernate 4 IllegalArgumentException:需要属性“sessionFactory”
【发布时间】:2014-05-22 13:23:23
【问题描述】:

我正在使用 Spring Data 和 Hibernate 编写 DAL,但遇到了 IllegalArgumentException 异常,该异常正在停止我的工作。

这里是 DALConf.java 类,其中包含 DataSource 和持久性异常翻译处理器配置

package my.dal.config;

import java.util.Properties;

import javax.annotation.Resource;
import javax.sql.DataSource;

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;


@Configuration
@ComponentScan(basePackages = { "my.dal" })
@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";

    @Resource
    private Environment environment;   

    @Bean
    public DataSource 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
    public PersistenceExceptionTranslationPostProcessor persistenceExceptionTranslationPostProcessor()
    {
        PersistenceExceptionTranslationPostProcessor b = new PersistenceExceptionTranslationPostProcessor();
        return b;
    }   
}

那么这里是 HibernateConfig.class 包含 Hibernate 配置

package my.dal.config;

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.HibernateExceptionTranslator;
import org.springframework.orm.hibernate4.HibernateTransactionManager;
import org.springframework.orm.hibernate4.LocalSessionFactoryBean;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@Configuration
@ComponentScan(basePackages = { "my.dal" })
@PropertySource("classpath:hibernate.properties")
@EnableTransactionManagement
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";
    private static final String PROPERTY_NAME_HIBERNATE_SHOW_SQL = "hibernate.showsql";

    @Resource
    private Environment environment;  

    @Autowired
    DataSource dataSource;

    @Bean
    public SessionFactory sessionFactory()
    {

        LocalSessionFactoryBean lsfb = new LocalSessionFactoryBean();

        lsfb.setPackagesToScan(environment.getProperty(PROPERTY_NAME_DAL_CLASSES_PACKAGE));

        Properties hibernateProperties = new Properties();
        hibernateProperties.put("dialect", environment.getProperty(PROPERTY_NAME_HIBERNATE_DIALECT));
        hibernateProperties.put("show_sql", environment.getProperty(PROPERTY_NAME_HIBERNATE_SHOW_SQL));

        lsfb.setHibernateProperties(hibernateProperties);
        lsfb.setDataSource(dataSource);
        return lsfb.getObject();

    }

    @Bean 
    public HibernateExceptionTranslator hibernateExceptionTranslator(){ 
      return new HibernateExceptionTranslator(); 
    }


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

}

这是 DAO UserDAO.java

package my.dal.dao;

import my.models.dal.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;


@Repository
public class UserDAO
{

    private SessionFactory sessionFactory;

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

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

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

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

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

}

最后,这是测试类DALTest.java

package my.dal.tests;

import static org.junit.Assert.assertTrue;
import my.dal.config.DALConfig;
import my.dal.config.HibernateConfig;
import my.dal.dao.UserDAO;
import my.models.dal.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.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

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

    @Autowired
    SessionFactory sessionFactory;

    @Test
    public void testGetUser() {
        UserDAO userDAO = new UserDAO(sessionFactory);
        User user = null;
        user = userDAO.getByUsername("mrossi");

        assertTrue(null != user);
    }

}

测试的执行以以下异常结束

...
Caused by: java.lang.IllegalArgumentException: Property 'sessionFactory' is required
    at org.springframework.orm.hibernate4.HibernateTransactionManager.afterPropertiesSet(HibernateTransactionManager.java:247)
    at org.springframework.orm.hibernate4.HibernateTransactionManager.<init>(HibernateTransactionManager.java:130)
    at my.dal.config.HibernateConfig.transactionManager(HibernateConfig.java:66)
...

在这一行抛出

HibernateTransactionManager htm = new HibernateTransactionManager(sessionFactory());

似乎 Spring 无法实例化 sessionFactory bean,但我不知道可能是什么问题...

你怎么看?

谢谢

【问题讨论】:

    标签: java hibernate spring-data illegalargumentexception sessionfactory


    【解决方案1】:

    你忘了打电话

    lsfb.afterPropertiesSet()
    

    在从lsfb 获取对象之前。 afterPropertiesSet() 是构建和公开会话工厂的方法。

    【讨论】:

    • 谢谢 :) 现在的问题是在这行代码(我实际使用会话的地方)user = userDAO.getByUsername("mrossi");我有另一个异常 org.hibernate.HibernateException: No Session found for current thread at org.hibernate.internal.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java: 941)在 it.prisma.dal.dao.UserDAO.getByUsername(UserDAO.java:36) 调试显示会话工厂已正确构建。我做错了什么?
    • 按照sendon的回答解决了
    【解决方案2】:

    解决此问题的一种方法是,您正在为 sessionFactory 使用构造函数注入,它不能很好地使用注释暴露的 bean。 (不确定 Spring 4 对此有何改进。我只使用 Spring 3.5 及以下版本)

    我建议在 UserDAO.java 中使用 getter/setter 方法注入

    private SessionFactory  sessionFactory;
    
    @Autowired
    public void setSessionFactory(SessionFactory sessionFactory)
    {
        this.sessionFactory = sessionFactory;
    }
    

    这样注解就可以拿到bean了。

    【讨论】:

    • 嗨,森登,谢谢。我已经按照您的建议编辑了代码,但现在我在 user = userDAO.getByUsername("mrossi"); 行得到了 NullPoinetrException奇怪的想法是调试显示 sessionFactory 在 setter 方法中正确实例化
    • 运行代码时出现异常:org.hibernate.service.UnknownUnwrapTypeException: Cannot unwrap to requested type [javax.sql.DataSource] 你有这个问题吗?
    • 奇怪,我没有得到那个异常(但是另一个与 Hibernate'Entity 一致的异常)。请记住,我在这篇文章中省略了实体类和属性文件。也许您的例外与这些信息缺乏有关?
    • 也许是这样。但是通常我们在使用spring+hibernate的时候,应该让spring来处理这些DB连接、数据源,而不是hibernate
    【解决方案3】:

    正如 JB Nizet 所建议的,如果您自己处理对象生命周期,则需要调用 afterPropertiesSet()。我想提出一个稍微好一点的配置版本来避免这个问题,你也可能在其他情况下遇到这个问题。

    每当您在 JavaConfig 中配置 FactoryBean 时,返回工厂并引用要在客户端方法上生成的实际对象。在您的示例中,这看起来像这样:

    @Configuration
    class YourConfig {
    
      @Bean
      public LocalSessionFactoryBean sessionFactory() {
        // setup factory
      }
    
      @Bean
      public HibernateTransactionManager transactionManager(SessionFactory factory) {
        return new HibernateTransactionManager(factory);
      }
    }
    

    如您所见,我们不会手动调用工厂的任何生命周期回调,因为我们必须按原样返回它。春天会为我们做到这一点。它还将在其上调用….getObject() 以创建实际的SessionFactory 并将其传递给@Bean 方法以创建事务管理器。

    【讨论】:

    • 感谢您的回复。我应该@Autowire transactionManager bean,以便根据 sessionFactory() bean 实例化 transactionManager 的工厂参数吗?
    • 好吧,不。事务管理器通常由 bean 名称检测,并且仅用于基础设施。简单地使用@Bean方法参数将导致Spring尝试解析参数类型的bean。
    猜你喜欢
    • 2015-06-10
    • 2014-01-06
    • 1970-01-01
    • 1970-01-01
    • 2016-07-14
    • 2013-06-07
    • 2012-01-23
    • 2014-09-02
    • 2016-07-22
    相关资源
    最近更新 更多