我使用Spring {x尝试了以下代码,但BeanNotFoundException
失败了,它应该根据我之前提出的问题的答案 - Can I inject same class using Spring?
@Service
public class UserService implements Service{
@Autowired
private Service self;
}
因为我在Java 6中尝试这个,所以我发现以下代码工作正常:
@Service(value = "someService")
public class UserService implements Service{
@Resource(name = "someService")
private Service self;
}
但我不明白它如何解决循环依赖。
编辑:
这是错误消息。 OP在其中一个答案的评论中提及它:
引起:org.springframework.beans.factory.NoSuchBeanDefinitionException:没有为依赖项找到[com.spring.service.Service]类型的匹配bean:期望至少有一个bean可以作为此依赖项的autowire候选者。依赖注释:{@ org.springframework.beans.factory.annotation.Autowired(required = true)}
答案 0 :(得分:42)
更新:2016年2月
Spring Framework 4.3将正式支持自动装配。可以在此GitHub commit中看到实现。
你不能自己动手的最终原因是Spring的DefaultListableBeanFactory.findAutowireCandidates(String, Class, DependencyDescriptor)
方法的实现明确排除了这种可能性。这在以下代码摘录中可见:
for (String candidateName : candidateNames) {
if (!candidateName.equals(beanName) && isAutowireCandidate(candidateName, descriptor)) {
result.put(candidateName, getBean(candidateName));
}
}
仅供参考:bean的名称(即尝试自动装配的bean)为beanName
。该bean实际上是一个autowire候选者,但上面的if-condition返回false(因为candidateName
实际上等于beanName
)。因此,您根本无法自动将bean自动装配(至少不是Spring 3.1 M1)。
现在至于这是否是从语义上讲的意图,这是另一个问题。 ;)
我会问Juergen,看看他有什么要说的。
此致
Sam(核心春天提交者)
P.S。我打开了一个Spring JIRA问题,考虑使用@Autowired支持自动装配类型。请在此处观看或投票支持此问题:https://jira.springsource.org/browse/SPR-8450
答案 1 :(得分:33)
此代码也适用:
@Service
public class UserService implements Service {
@Autowired
private ApplicationContext applicationContext;
private Service self;
@PostConstruct
private void init() {
self = applicationContext.getBean(UserService.class);
}
}
我不知道为什么,但是如果创建了,那么Spring似乎可以从ApplicationContext
获取bean,但不能初始化。 @Autowired
在初始化之前工作,但找不到相同的bean。因此,@Resource
可能在@Autowired
之后和@PostConstruct
之前有效。
但我不知道,只是推测。无论如何,好问题。
答案 2 :(得分:1)
鉴于上面的代码,我没有看到循环依赖。 您将一些Service实例注入UserService。 注入的Service的实现不一定需要是另一个UserService,因此没有循环依赖。
我不明白你为什么要把UserService注入UserService,但我希望这是一个理论上的尝试等等。
答案 3 :(得分:1)
顺便说一下,自我调用问题的更优雅的解决方案是为事务代理(或者您使用的任何AOP引入的代理)使用AspectJ Load-Time Weaving。
例如,使用注释驱动的事务管理,您可以使用“aspectj”模式,如下所示:
<tx:annotation-driven mode="aspectj" />
请注意,默认模式是“proxy”(即JDK动态代理)。
此致
萨姆
答案 4 :(得分:1)
Get AOP proxy from the object itself问题提出了AopContext.currentProxy()
替代hacky方法,可能适用于特殊情况。
答案 5 :(得分:0)
看起来spring创建并配置一个对象,然后将它放在bean查找上下文中。但是,在Java的情况下,我认为它创建了对象并将其与名称和配置期间绑定,当通过上下文中找到的名称查找对象时。
答案 6 :(得分:0)
另一个方法:
@EnableAsync
@SpringBootApplication
public class Application {
@Autowired
private AccountStatusService accountStatusService;
@PostConstruct
private void init() {
accountStatusService.setSelf(accountStatusService);
}
}
@Service
public class AccountStatusService {
private AccountStatusService self;
public void setSelf(AccountStatusService self) {
this.self = self;
}
}
与此相关,您的服务将在代理中。我这样做是为了在其内部使用异步方法。
我尝试了@sinuhepop解决方案:
@PostConstruct
private void init() {
self = applicationContext.getBean(UserService.class);
}
它进行了注入,但是该服务不在代理内部,并且我的方法未在新线程上运行。有了这个方法,它就可以像我想要的那样工作。
答案 7 :(得分:0)
这是我针对中小型项目的解决方案。没有AspectJ或应用程序上下文魔术,它可用于单例和构造函数注入,并且非常易于测试。
@Service
@Scope(proxyMode = ScopedProxyMode.TARGET_CLASS)
class PersonDao {
private final PersonDao _personDao;
@Autowired
public PersonDao(PersonDao personDao) {
_personDao = personDao;
}
}