Java 弹簧自注入
我用Spring 3.x尝试了以下代码,但失败了Java 弹簧自注入,java,spring,dependency-injection,ioc-container,Java,Spring,Dependency Injection,Ioc Container,我用Spring 3.x尝试了以下代码,但失败了BeanNotFoundException,应该是根据我之前问过的一个问题的答案- 由于我在Java 6中尝试了这一点,我发现以下代码可以正常工作: @Service(value = "someService") public class UserService implements Service{ @Resource(name = "someService") private Service self; } 但我不明白它是如何
BeanNotFoundException
,应该是根据我之前问过的一个问题的答案-
由于我在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:至少需要1个符合此依赖项autowire候选项条件的bean。依赖项注释:{@org.springframework.beans.factory.annotation.Autowired(required=true)}
给出上述代码,我看不到循环依赖关系。 您将服务的某个实例注入到UserService中。 注入服务的实现不一定需要是另一个UserService,因此不存在循环依赖关系
我不明白为什么要将UserService注入UserService,但我希望这是一次理论上的尝试。看起来spring创建并配置了一个对象,然后将其放在bean查找上下文中。但是,在Java的情况下,我认为它创建了对象,并将其与名称和配置绑定在一起,当通过在上下文中找到的名称查找对象时 此代码也适用:
@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
之前工作
但我不知道,只是猜测而已。无论如何,好问题。更新:2016年2月 SpringFramework4.3将正式支持自动布线。从这一点可以看出实施情况
无法自动连线的最终原因是Spring的
DefaultListableBeanFactory.FinDautoWire候选(字符串、类、DependencyDescriptor)
方法的实现明确排除了这种可能性。从该方法的以下代码摘录中可以看到这一点:
for (String candidateName : candidateNames) {
if (!candidateName.equals(beanName) && isAutowireCandidate(candidateName, descriptor)) {
result.put(candidateName, getBean(candidateName));
}
}
仅供参考:bean的名称(即尝试自动连接自身的bean)是beanName
。该bean实际上是一个autowire候选者,但上面的if条件返回false(因为candidateName
实际上等于beanName
)。因此,您无法将bean与自身自动关联(至少在Spring3.1M1中是这样)
现在,从语义上讲,这是否是有意的行为,这是另一个问题
我去问问尤尔根,看看他有什么话要说
问候,
Sam(核心弹簧提交人)
我已经打开了一个Spring JRRA问题,考虑使用@ AutoRoD支持类型自动自偿。请随意观看或投票:顺便说一下,对于自调用问题,更优雅的解决方案是使用AspectJ加载时编织用于事务代理(或使用AOP引入的任何代理) 例如,对于注释驱动的事务管理,您可以使用“aspectj”模式,如下所示:
<tx:annotation-driven mode="aspectj" />
请注意,默认模式是“代理”(即JDK动态代理)
问候,
Sam问题建议使用适用于特殊情况的AopContext.currentProxy()替代黑客方法。仅是另一种方法:
@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);
}
它进行了注入,但服务不在代理内,我的方法也没有在新线程上运行。这是我为中小型项目提供的解决方案。没有AspectJ或应用程序上下文魔术,它与单例和构造函数注入一起工作,并且非常容易测试
@Service
@Scope(proxyMode = ScopedProxyMode.TARGET_CLASS)
class PersonDao {
private final PersonDao _personDao;
@Autowired
public PersonDao(PersonDao personDao) {
_personDao = personDao;
}
}
我只有一个服务实现,那就是UserService:)。。相同的代码在Spring@Autowired中失败,但在@resource中工作如果服务在其周围使用Spring缓存代理,并且您希望内部调用从该缓存中受益,那么将bean连接到自身可能很有用。aspectj可以与JDK代理一起工作吗?我想它需要CGLib,对吗?aspectj处理自调用,但会产生其他问题,而且上次我检查时不推荐使用SpringSource文档。@Amit-这确实解释了!!它们只排除自动连接的候选对象,而不检查其他候选对象,如@Resource等。我认为这样的方法在某些情况下非常有用,例如,有时需要使用事务代理(特别是requires_new)包装方法,该代理可以自调用。必须“分离”这样的功能通常会导致反模式和糟糕的设计。与NVR一致,同一类
@Transactional
代理是导致我出现这种情况的原因。当您有一个成熟的代码库时,“使用AspectJ而不是CGLib”不是一个有用的答案。使用@Resource
可能会解决我的问题,但@Autowired
更可取,因为这是我们的标准。@Xiangyu,Juergen Hoeller三天前刚刚记录了这一点:记住添加@Lazy
很酷,将上下文注入到应用程序bean中。这是有史以来最好的实践@avrilfanomar:好吧,如果一个类需要意识到它本身有一个代理,那么无论如何你都在破坏DI抽象,所以我认为访问你的容器并不是更糟。为什么它会破坏DI?我认为注入self并没有什么坏处,比如说,它应该使用事务性方法。我在上面用UserService类中的更多字段做了同样的尝试。但当我做self.morefield.xxx时。它提出了一个问题:自我注入的目的是什么
@Service
@Scope(proxyMode = ScopedProxyMode.TARGET_CLASS)
class PersonDao {
private final PersonDao _personDao;
@Autowired
public PersonDao(PersonDao personDao) {
_personDao = personDao;
}
}