1

我试图从现有应用程序中分离出 Hibernate DAO 和模型对象层,以便它们可以跨多个应用程序使用。不幸的是,我没有取得太大的成功:尝试从应用程序上下文中获取 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);
   }
}
4

3 回答 3

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);
   }
}

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

于 2012-08-20T13:12:50.817 回答
1

为了将 SessionFactory 连接到您的自定义通用 DAO,您可以继续并简单地使用 @Autowire,只要整个 Spring 上下文正在定义 SessionFactory bean。要定义 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 并对其进行配置。

希望这可以帮助。

于 2012-08-20T12:51:38.737 回答
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-->

于 2013-06-13T18:19:14.277 回答