1

我正在尝试自动装配由存储库工厂 bean 创建的存储库。我需要使用自定义代码覆盖某些存储库的 save() 方法。我在Spring Data 的介绍中遵循了工厂 bean 的示例。

但无论我做什么,我都会得到NoSuchBeanDefinitionException

另一方面,“仅接口存储库”的创建和注入就好了。

很可能我在某个地方犯了一个愚蠢的错误。因为这应该是 Spring Data 101。

有人可以给我一个线索,让我知道我还可以尝试使它发挥作用吗?

规格

休眠 4.1.9.Final

Spring 3.2.1.RELEASE

Spring Data 1.3.0.RELEASE

JDK 1.6.0_39。

Arch Linux x64

存储库工厂

如果实体是 Bar 类型,我将返回一个不同的存储库。否则将应用默认行为。

public class RepositoryFactoryBean<R extends JpaRepository<T, I>, T, I extends Serializable>  extends JpaRepositoryFactoryBean<R, T, I> {

  protected RepositoryFactorySupport createRepositoryFactory(EntityManager entityManager) {
    return new MyRepositoryFactory(entityManager);
  }

  private static class MyRepositoryFactory<T, I extends Serializable> extends JpaRepositoryFactory {

    private EntityManager entityManager;

    public MyRepositoryFactory(final EntityManager entityManager) {
      super(entityManager);
      this.entityManager = entityManager;
    }

    protected Object getTargetRepository(final RepositoryMetadata metadata) {
      if (metadata.getDomainType().equals(Bar.class)) {
        return new BarDaoImpl((Class<Bar>) metadata.getDomainType(), entityManager);
      }
      return super.getTargetRepository(metadata);
    }

    protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {
      if (metadata.getDomainType().equals(Bar.class)) {
        return BarDao.class;
      }
      return super.getRepositoryBaseClass(metadata);
    }
  }
}

存储库类和接口

package com.bar.persistence.dao;

@NoRepositoryBean
public interface BarDao extends JpaRepository<Bar, Long> {
  // no methods - because I want to override save()
}



package com.bar.persistence.dao;

public class BarDaoImpl extends SimpleJpaRepository<Bar, Long> implements BarDao {

  public BarDaoImpl(final Class<Bar> domainClass, final EntityManager em) {
    super(domainClass, em);
  }

  @Override
  public <S extends Bar> S save(final S entity) {
    // some code to perform before actually saving the entity
    entity.setName("intercepted save !");

    // do the save
    return super.save(entity);
  }
}

注入存储库的测试

测试失败,因为它找不到要注入的 BarDao 类型的 bean。

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("/persistence-beans.xml")
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS)
@TransactionConfiguration
public class SpringDataLearningTest {

  @Autowired
  private BarDao barDao;

  @Transactional
  @Test
  public void testModifiedSave() throws Exception {
    final Bar original = createRandomBar();
    final Bar saved = barDao.save(original);
    assertNotNull("No id was assigned to the saved entity", saved.getId());
    assertEquals("intercepted save !", saved.getName());
  }

  private static Bar createRandomBar() {...}
}

弹簧配置

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

  <!-- Tell Spring Data where to find the interfaces -->
  <data:repositories base-package="com.bar.persistence.dao" factory-class="com.bar.persistence.dao.RepositoryFactoryBean"/>

  <!-- include the definitions of the 'upstream' modules -->
  <import resource="common-beans.xml"/>
  <import resource="io-beans.xml"/>

  <!-- The exception translator service-->
  <bean class="org.springframework.orm.hibernate4.HibernateExceptionTranslator"/>

  <bean id="jpaTemplate" class="org.springframework.orm.jpa.JpaTemplate">
    <property name="entityManagerFactory" ref="entityManagerFactory"/>
  </bean>

  <!-- Use the classic Spring JPA Transaction Manager -->
  <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory"/>
  </bean>

  <!-- Describes how to connect to the database -->
  <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
    <property name="user" value="${database.user.name}"/>
    <property name="password" value="${database.user.password}"/>
    <property name="driverClass" value="${database.driver}"/>
    <property name="jdbcUrl" value="${database.url}"/>
    <property name="initialPoolSize" value="1"/>
    <property name="maxPoolSize" value="${database.max.pool.size}"/>
    <property name="minPoolSize" value="${database.min.pool.size}"/>
    <property name="acquireIncrement" value="1"/>
    <property name="acquireRetryAttempts" value="3"/>
    <property name="checkoutTimeout" value="10000"/>
  </bean>

  <!-- Describes how to create hibernate sessions -->
  <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="persistenceProviderClass" value="org.hibernate.ejb.HibernatePersistence"/>
    <property name="persistenceUnitName" value="bars"/>
    <property name="dataSource" ref="dataSource"/>
    <property name="jpaProperties">
      <props>
        <prop key="hibernate.cache.region.factory_class">${hibernate.cache.region.factory_class}</prop>
        <prop key="hibernate.cache.use_second_level_cache">${hibernate.second.level.cache}</prop>
        <prop key="hibernate.cache.use_query_cache">${hibernate.query.cache}</prop>
        <prop key="hibernate.generate_statistics">true</prop>
        <prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop>
        <prop key="hibernate.jdbc.batch_size">${hibernate.jdbc.batch_size}</prop>
        <prop key="hibernate.show_sql">${database.show.sql}</prop>
        <prop key="hibernate.dialect">${database.hibernate.dialect}</prop>
        <prop key="hibernate.search.default.directory_provider">filesystem</prop>
        <prop key="hibernate.search.default.indexBase">${hibernate.search.dir}</prop>
      </props>
    </property>
  </bean>
</beans>

堆栈跟踪

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'com.bar.persistence.dao.SpringDataLearningTest': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.bar.persistence.dao.barDao com.bar.persistence.dao.SpringDataLearningTest.barDao; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.bar.persistence.dao.BarDao] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:288)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1120)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireBeanProperties(AbstractAutowireCapableBeanFactory.java:379)
    at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:110)
    at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:75)
    at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:313)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:211)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:288)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:284)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:231)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:88)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:160)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:76)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:195)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:63)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.bar.persistence.dao.BarDao com.bar.persistence.dao.SpringDataLearningTest.barDao; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.bar.persistence.dao.BarDao] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:514)
    at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:87)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:285)
    ... 29 more
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.bar.persistence.dao.BarDao] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:967)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:837)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:749)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:486)
    ... 31 more
4

1 回答 1

2

像这样的东西:

  1. @NoRepositoryBean_BarDao
  2. 添加@NoRepositoryBeanBarDaoImpl
  3. 移动到BarDaoImpl_BarDaocom.bar.persistence.dao.bar
  4. 添加新interface BarDaoMyRepository extends BarDaocom.bar.persistence.dao.repository
  5. base-package="com.bar.persistence.dao.repository"
  6. 注入BarDaoMyRepository

您使用方法向每个扩展的存储库添加一些功能BarDao(因此您需要扩展它并可能添加一些声明性方法)。如果您只想向一个存储库添加功能 - 请参阅

http://static.springsource.org/spring-data/data-jpa/docs/current/reference/html/repositories.html#repositories.introduction 1.4.1 向单个存储库添加行为

于 2013-02-28T22:10:05.423 回答