使用Hibernate在JAR中使用Spring的难度

时间:2012-08-20 12:25:50

标签: java hibernate jar

我正在尝试从现有应用程序中拆分Hibernate DAO和Model Object层,以便可以跨多个应用程序使用它们。不幸的是,我没有取得多大成功:尝试从应用程序上下文中获取SessionFactory时会抛出NoSuchBeanDefinitionException。

所有DAO类都扩展了一个名为GenericDaoHibernate2的类。每个DAO都扩展它,并在构造函数中传递一个Class。非常标准的通用DAO东西。

我认为这也是设置会话工厂的合理位置(有很多DAO类)。所以,在构造函数类中,我这样做了:

public GenericDaoHibernate2(final Class<T> persistentClass) {
    ctx = new ClassPathXmlApplicationContext("META-INF/applicationContext-dao.xml");
    this.sessionFactory = (SessionFactory) ctx.getBean(SessionFactory.class);
    log.debug("Value of app context: " + ctx.toString());
    log.debug("Value of sessionFactory: " + sessionFactory);
    this.persistentClass = persistentClass;
}

不幸的是,这与前面提到的异常相混淆:

Caused By: org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [org.hibernate.SessionFactory] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:924)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:793)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:707)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.inject(AutowiredAnnotationBeanPostProcessor.java:551)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:87)
Truncated. see log file for complete stacktrace

我还尝试使用类路径中的应用程序上下文文件,在声明变量时设置值等等。

我正在猜测正在讨厌的是,作为Maven构建的一部分,jar没有引用类路径上的库,但我真的不知道...

更新:愚蠢,愚蠢我......忘了显示应用程序上下文文件。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
     http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
       http://www.springframework.org/schema/context 
       http://www.springframework.org/schema/context/spring-context-3.1.xsd
       http://www.springframework.org/schema/jee
       http://www.springframework.org/schema/jee/spring-jee-3.1.xsd
       http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd"
    default-lazy-init="true">

    <tx:annotation-driven transaction-manager="transactionManager" />
    <context:component-scan base-package="org.jason.dao.hibernate" />


    <bean id="dataSource"
        class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
        <property name="url" value="jdbc:oracle:thin:@//192.168.1.1/db01" />
        <property name="username" value="USER" />
        <property name="password" value="PASSWORD" />
    </bean>

    <!-- Hibernate SessionFactory -->
    <bean id="sessionFactory"
        class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop>
                <prop key="hibername.format_sql">true</prop>
                <prop key="hibernate.show_sql">true</prop>
                <prop key="hibernate.jdbc.use_get_generated_keys">true</prop>
                <prop key="hibernate.cglib.use_reflection_optimizer">true</prop>
                <prop key="hibernate.default_catalog">CATALOG</prop>
                <prop key="hibernate.cache.use_second_level_cache">true</prop>
                <prop key="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory
                </prop>
            </props>
        </property>
        <property name="packagesToScan">
            <list>
                <value>org.jason.model</value>
            </list>
        </property>
    </bean>
</beans>

另一个更新:被要求提供样本DAO。接口是一个“标准”通用接口,接受通用参数T和PK,就像Impl一样。除了从GenericDaoHibernate2继承的内容之外,以下内容没有任何具体方法。

@Repository("AreaOfPreferenceDAO")
public class HibernateAreaOfPreferenceDAO extends GenericDaoHibernate2<AreaOfPreference, AreaOfPreferenceCompositeId> implements AreaOfPreferenceDAO {

   public HibernateAreaOfPreferenceDAO()
   {
      super(AreaOfPreference.class);
   }
}

3 个答案:

答案 0 :(得分:1)

为了将SessionFactory连接到您的自定义通用DAO中,只要整个Spring上下文定义了SessionFactory bean,您就可以继续使用@Autowire。 要定义bean:

<bean id="sessionFactory" class=
    "org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
   <property name="dataSource" ref="dataSource" />
   <property name="packagesToScan" value="org.rest" />

   <property name="hibernateProperties">
      ...
   </property>
</bean>
<bean id="dataSource" class=
    "org.springframework.jdbc.datasource.DriverManagerDataSource">
   <property name="driverClassName" value="${driverClassName}" />
   <property name="url" value="${url}" />
   <property name="username" value="restUser" />
   <property name="password" value="restmy5ql" />
</bean>

简单地说:

@Autowired
SessionFactory sessionFactory;

引导上下文的正确位置不在DAO的构造函数中;如果您正在使用Web应用程序,则可以采用传统方法:

<servlet>
   <servlet-name>dispatcher</servlet-name>
   <servlet-class>
     org.springframework.web.servlet.DispatcherServlet
   </servlet-class>
   <init-param>
     <param-name>contextConfigLocation</param-name>
     <param-value>/WEB-INF/spring/dispatcher-config.xml</param-value>
   </init-param>
   <load-on-startup>1</load-on-startup>
 </servlet>

 <servlet-mapping>
   <servlet-name>dispatcher</servlet-name>
   <url-pattern>/</url-pattern>
 </servlet-mapping>

由于这不是Web应用程序,因此无法在web.xml中引导上下文;但是,引导仍然需要是外部的 - 主类只需要创建XmlWebApplicationContext并进行配置。

希望这会有所帮助。

答案 1 :(得分:1)

您在每个DAO对象中创建新的应用程序上下文这一事实可能会让您遇到麻烦。

ctx = new ClassPathXmlApplicationContext("META-INF/applicationContext-dao.xml");

如果你想一想,这是一种循环。你调用上下文,它对DAO进行组件扫描,然后DAO实例化一个新的上下文,它为DAO的组件扫描......

我会像其他人提到的那样直接自动发送sessionfactory。

@Repository("AreaOfPreferenceDAO")
public class HibernateAreaOfPreferenceDAO extends GenericDaoHibernate2<AreaOfPreference, AreaOfPreferenceCompositeId> implements AreaOfPreferenceDAO {

   @Autowired
   public HibernateAreaOfPreferenceDAO(SessionFactory sessionFactory)
   {
      super(sessionFactory, AreaOfPreference.class);
   }
}

任何组件都不需要构建新的应用程序上下文。

答案 2 :(得分:0)

遇到同样的问题,无法进行注射工作。

我的问题是“序列”。必须首先调用Hibernate xml。

调度-servlet.xml中:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.1.xsd
    http://www.springframework.org/schema/mvc
    http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd">

<!-- init hibernate first -->
<import resource="classpath:HibernateContext.xml"/>

<bean id="viewResolver"
    class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix" value="/WEB-INF/pages/" />
    <property name="suffix" value=".jsp" />
</bean>
<mvc:annotation-driven />
<context:component-scan base-package="com.xxx.yyy" />

hibernateContext.xml的内容:

<beans xmlns="http://www.springframework.org/schema/beans"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns:tx="http://www.springframework.org/schema/tx"
   xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">

<bean id="propertyConfigurer"
    class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="locations">
        <list>
            <value>classpath:database.properties</value>
        </list>
    </property>
</bean>

<bean id="dataSource"
    class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="${jdbc.driver}" />
    <property name="url" value="${jdbc.url}" />
    <property name="username" value="${jdbc.user}" />
    <property name="password" value="${jdbc.password}" />
</bean>

<bean id="sessionFactory"
    class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <property name="packagesToScan" value="com.xxx.yyy.model" />
    <property name="hibernateProperties">
        <props>
            <prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop>
            <prop key="hibernate.show_sql">true</prop>
        </props>

    </property>
</bean>

<tx:annotation-driven transaction-manager="transactionManager"/>

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

<!--  bean id="transactionManager" class=" org.springframework.transaction.jta.JtaTransactionManager">
    <property name="sessionFactory" ref="sessionFactory"/>
</bean-->