
你会看到三种方式的真实对比:比如构造器注入怎么帮你避免空指针问题,Setter注入为啥更适合可选依赖,字段注入的简洁性背后又藏着哪些坑。我还会结合自己带团队时遇到的案例——像Service层依赖多个Dao组件时怎么配置更清晰,老项目从XML迁移到注解时要注意啥——手把手教你避开常见错误。
最实用的是,文章里不光有理论,还会带你一步步排查注入失败的问题(比如依赖没扫描到、注解用混了),甚至连循环依赖这种头疼问题的解决方案都给你准备好了。读完这篇,你不仅能搞懂每种注入方式的原理,还能直接把代码抄到项目里用,下次再遇到依赖注入的问题,就能像老司机一样轻松搞定。
@Autowired和@Resource这两个注解,你平时开发时是不是经常混用?其实它们背后的逻辑差得还挺远的。先说说@Autowired,这是Spring自家的注解,所以它默认是按类型(byType)来找Bean的。啥意思呢?比如你在Service里写@Autowired private UserDao userDao;,Spring就会去容器里找类型是UserDao的Bean,找到了就给你注入进来。但这里有个坑,我带团队的时候,好几个新人都踩过——如果容器里有两个UserDao的实现类(比如UserDaoImpl和UserDaoMock),这时候@Autowired就懵了,不知道该选哪个,直接给你报NoUniqueBeanDefinitionException。这时候就得配上@Qualifier注解,明确告诉它要哪个,比如@Qualifier(“userDaoImpl”),这样才能精准定位。
再来说@Resource,这玩意儿是JDK原生的注解,不是Spring特有的,所以它默认是按名称(byName)来找Bean的。比如你写@Resource private UserDao userDao;,Spring会先看变量名“userDao”,去容器里找id或name是“userDao”的Bean。如果想指定别的名称,直接加个name属性就行,像@Resource(name = “userDaoMock”),特别灵活。不过它有个小脾气——不认Spring的@Primary注解。之前有个项目,我们给UserDaoImpl加了@Primary想让它成为默认,但有个同事用@Resource注入,结果还是按名称找,死活没选中@Primary的那个,排查半天才发现是这个原因。实际开发里,如果你的项目以后可能脱离Spring框架,用@Resource会更解耦;如果想严格遵循Spring的依赖注入规范,那构造器注入配合@Autowired会更靠谱,毕竟能显式声明依赖关系,代码可读性也更好。
三种依赖注入方式应该优先选择哪种?
在实际开发中,推荐优先使用构造器注入,因为它能保证依赖对象在创建时就被初始化(避免空指针异常),且明确表达强依赖关系;Setter注入适合可选依赖(如非必需的配置类),灵活性更高;字段注入虽简洁但会增加测试难度,且可能导致循环依赖问题, 仅在简单场景或遗留项目中使用。
Spring如何解决循环依赖问题?
Spring通过三级缓存机制处理循环依赖:当A依赖B、B依赖A时,Spring会先创建A的半成品对象放入缓存,再去创建B,B创建时从缓存获取A的半成品完成注入,最后A从缓存获取B的完整对象完成初始化。但构造器注入无法解决循环依赖,需改用Setter注入或字段注入,并确保依赖非强必需。
注入失败时常见的排查方向有哪些?
注入失败通常有三类原因:① 依赖类未被Spring扫描(检查@ComponentScan注解范围或XML配置的base-package);② 注解使用错误(如@Autowired与@Resource混用导致类型/名称匹配失败);③ 依赖类型不唯一(存在多个同类型Bean时需用@Qualifier指定名称)。可通过Spring日志的“No qualifying bean”错误提示定位具体问题。
@Autowired和@Resource注解有什么区别?
@Autowired是Spring自带注解,默认按类型注入,需配合@Qualifier指定名称;@Resource是JDK原生注解,默认按名称注入,可通过name属性显式指定,不支持@Primary注解优先级。实际开发中,推荐@Resource(解耦Spring框架)或构造器注入(更符合依赖倒置原则)。
字段注入的“坑”主要体现在哪里?
字段注入的缺点包括:① 无法通过构造函数保证依赖非空,运行时可能出现NullPointerException;② 依赖关系隐藏在字段上,代码可读性差(需通读类才能发现依赖);③ 不利于单元测试(无法通过构造函数 mock 依赖对象,需依赖Spring容器)。Spring官方文档也 避免过度使用字段注入。