女士们和女士们的问候,
我正在实施一个系统,我们正在努力保持高度灵活性。我们有一个名为EmailTaskService
的抽象超类,它有两个继承自它的类。一个是EmailTaskServiceImpl
(具体实现类),另一个是另一个名为ScheduledEmailTaskService
的抽象类,它有一个名为ScheduledEmailTaskServiceImpl
的子类。
为了保持灵活性,我们在ScheduledEmailTaskService
上同时使用垂直和水平装饰器模式。这意味着它继承自EmailTaskService
以及在具体服务本身中进行组合。但我的问题来自尝试自动装配具体EmailTaskServiceImpl
,我得到的只是抛出No qualifying bean of type EmailTaskServiceImpl
异常。显然,我不能只是自动装配EmailTaskService
,因为它是一个抽象类,而不是接口。
我会发布下面的代码,让你知道发生了什么 EmailTaskService
public abstract class EmailTaskService<E, I> implements GenericService<E, I>{
@Autowired
protected EmailTaskDAO emailTaskDao;
public abstract void deleteEmailTask(I emailTaskId);
}
EmailTaskServiceImpl
@Service("emailTaskService")
public class EmailTaskServiceImpl extends EmailTaskService<EmailTask, Long>{
@Override
@Transactional
public long getTotalObjects() {
return super.emailTaskDao.count();
}
etc etc other methods here doing concretey things.
ScheduledEmailTaskService
public abstract class ScheduledEmailTaskService<E, I> extends EmailTaskService<E, I> {
@Autowired
protected ScheduledEmailTaskDAO scheduledEmailTaskDao;
@Autowired
@Qualifier("emailTaskService")
protected EmailTaskService<EmailTask, Long> emailTaskService;
@Override
public abstract void deleteEmailTask(I emailTaskId) throws InvalidInvocationException;
public abstract void deleteScheduledEmailTask(I scheduledEmailTaskId);
}
ScheduledEmailTaskService
@Service
public class ScheduledEmailTaskServiceImpl extends ScheduledEmailTaskService<ScheduledEmailTask, Long> {
@Override
@Transactional
public long getTotalObjects() {
return super.scheduledEmailTaskDao.count();
}
more concretey methods go here
如果您想知道GenericService<E, I>
是一个为我的所有服务指定CRUD方法的接口,这就是EmailTaskService
实现它的原因。
所以我的问题是如何通过自动装配或其他明智的方法获得EmailTaskService
或EmailTaskServiceImpl
在ScheduledEmailTaskService
中成功提供的某种引用。如果这不可能,为什么?
编辑1(上下文配置): 问,你会得到:
<beans Spring namespace config etc etc etc>
<context:component-scan base-package="au.com.mail" />
<mvc:annotation-driven />
<tx:annotation-driven />
<task:annotation-driven/>
<!-- Project Properties -->
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<value>classpath:project.properties</value>
</property>
</bean>
</beans>
编辑2:实际正确的Stacktrace:
[junit] Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'scheduledEmailTaskServiceImpl': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: protected au.com.mail.service.emailtask.EmailTaskService au.com.mail.service.emailtask.ScheduledEmailTaskService.emailTaskService; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [au.com.mail.service.emailtask.EmailTaskService] 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), @org.springframework.beans.factory.annotation.Qualifier(value=emailTaskService)}
[junit] at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:289)
[junit] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1146)
[junit] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:519)
[junit] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:458)
[junit] at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:296)
[junit] at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223)
[junit] at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:293)
[junit] at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
[junit] at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:628)
[junit] at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:932)
[junit] at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:479)
[junit] at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:120)
[junit] at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:60)
[junit] at org.springframework.test.context.support.AbstractDelegatingSmartContextLoader.delegateLoading(AbstractDelegatingSmartContextLoader.java:100)
[junit] at org.springframework.test.context.support.AbstractDelegatingSmartContextLoader.loadContext(AbstractDelegatingSmartContextLoader.java:248)
[junit] at org.springframework.test.context.CacheAwareContextLoaderDelegate.loadContextInternal(CacheAwareContextLoaderDelegate.java:64)
[junit] at org.springframework.test.context.CacheAwareContextLoaderDelegate.loadContext(CacheAwareContextLoaderDelegate.java:91)
[junit] ... 50 more
[junit] Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: protected au.com.mail.service.emailtask.EmailTaskService au.com.mail.service.emailtask.ScheduledEmailTaskService.emailTaskService; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [au.com.mail.service.emailtask.EmailTaskService] 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), @org.springframework.beans.factory.annotation.Qualifier(value=emailTaskService)}
[junit] at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:517)
[junit] at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:87)
[junit] at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:286)
[junit] ... 66 more
[junit] Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [au.com.mail.service.emailtask.EmailTaskService] 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), @org.springframework.beans.factory.annotation.Qualifier(value=emailTaskService)}
[junit] at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:988)
[junit] at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:858)
[junit] at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:770)
[junit] at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:489)
[junit] ... 68 more
在你问之前,是的,我的JUnit被配置为正确使用Spring Application Context。
答案 0 :(得分:3)
鉴于您到处都有@Transactional
,我将假设您正在使用JDK代理进行代理。
事实证明,JKD代理只能获取目标bean的接口,而不是它们的类层次结构。因此,为EmailTaskServiceImpl
创建的代理不属于EmailTaskServiceImpl
类型,因此无法填写该类型的注入目标。相反,它的类型为EmailTaskService
,但您的字段为
@Autowired
protected EmailTaskServiceImpl emailTaskService;
所以不会这样做。
有两种解决方案:
首先是更改配置以使用CGLIB代理。您需要将交易配置更改为
<tx:annotation-driven proxy-target-class="true" />
并将CGLIB库添加到类路径中。
第二种是将你的领域改为
@Autowired
@Qualifier("someName")
protected EmailTaskService emailTaskService;
和您的班级声明
@Service("someName")
public class EmailTaskServiceImpl extends EmailTaskService<EmailTask, Long>{
在确定要注入哪个bean时,Spring将使用名称而不是类型。这是必要的,因为你有许多EmailTaskService
候选bean。