我正在尝试自动装配由存储库工厂 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