Spring 编程常见错误 50 例
傅健
Cisco 高级软件工程师、Netty 源码贡献者
16515 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 29 讲
结束语 (1讲)
期末测试 (1讲)
Spring 编程常见错误 50 例
15
15
1.0x
00:00/00:00
登录|注册

02|Spring Bean 依赖注入常见错误(上)

你好,我是傅健,这节课我们来聊聊 Spring @Autowired。
提及 Spring 的优势或特性,我们都会立马想起“控制反转、依赖注入”这八字真言。而 @Autowired 正是用来支持依赖注入的核心利器之一。表面上看,它仅仅是一个注解,在使用上不应该出错。但是,在实际使用中,我们仍然会出现各式各样的错误,而且都堪称经典。所以这节课我就带着你学习下这些经典错误及其背后的原因,以防患于未然。

案例 1:过多赠予,无所适从

在使用 @Autowired 时,不管你是菜鸟级还是专家级的 Spring 使用者,都应该制造或者遭遇过类似的错误:
required a single bean, but 2 were found
顾名思义,我们仅需要一个 Bean,但实际却提供了 2 个(这里的“2”在实际错误中可能是其它大于 1 的任何数字)。
为了重现这个错误,我们可以先写一个案例来模拟下。假设我们在开发一个学籍管理系统案例,需要提供一个 API 根据学生的学号(ID)来移除学生,学生的信息维护肯定需要一个数据库来支撑,所以大体上可以实现如下:
@RestController
@Slf4j
@Validated
public class StudentController {
@Autowired
DataService dataService;
@RequestMapping(path = "students/{id}", method = RequestMethod.DELETE)
public void deleteStudent(@PathVariable("id") @Range(min = 1,max = 100) int id){
dataService.deleteStudent(id);
};
}
其中 DataService 是一个接口,其实现依托于 Oracle,代码示意如下:
public interface DataService {
void deleteStudent(int id);
}
@Repository
@Slf4j
public class OracleDataService implements DataService{
@Override
public void deleteStudent(int id) {
log.info("delete student info maintained by oracle");
}
}
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结
仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《Spring 编程常见错误 50 例》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(20)

  • 最新
  • 精选
  • liuchao90h
    要是变量中也能做到可以包含.号就可以了,或者源码中把包分隔符的.改成下划线来解决 对于例子中的com.spring.puzzle.class2.example3.StudentController.InnerClassDataService建议换成com.spring.puzzle.class2.example3.StudentController$InnerClassDataService更规范,否则对照源码截图是会误解的,本身也不是语法规范的写法,尽管意思明白的人都能明白过来
    1
    28
  • 楼下小黑哥
    好家伙,咋一看这个问题,感觉跟 @Qualifier 注解应该是一样的,应该可以使用字段名 tudentController.InnerClassDataService 这样的方式。 但是看起来还是有点别扭,于是复制到 IDEA 试了下,原来这样语法有问题,直接就会报错😂。 大意了~ 赞同 @liuchao90h 说法,内部类实际取到名字应该为 com.xxxx. StudentController$InnerClassDataService
    9
  • Niverkk
    内部类类名:com.spring.puzzle.class2.example3.StudentController.InnerClassDataService 应该是:com.spring.puzzle.class2.example3.StudentController$InnerClassDataService, "."换成"$"
    1
    4
  • 暖色浮余生
    其实可以通过重写BeanNameGenerator来自己实现bean名称的实现。看了下ComponentScanAnnotationParser的源码。发现在parse方法里面会获取注解 @ComponentScan的nameGenerator属性。获取到NameGenerator的Class。然后实例化设置到ClassPathBeanDefinitionScanner这个扫描类的 BeanNameGenerator属性上面。 这样的话@AutowiredDataService innerClassDataService;通过自定义的Bean名称生成器来注入就可以了
    4
  • KK
    为什么一定要看源码? 源码不是一种契约, 是可能变化的, 而且学习成本高. 学习Spring的官方文档更加好, 官方文档所阐述的特性, 可以认为是spring的开发者和使用者的契约, 是相对不容易变化的.
    2
    3
  • 安迪密恩
    傅哥你好,现在@Autowired注解被IDEA标记为Field injection is not recommended。为什么呢?能否请傅哥扩展下@Resource的相关知识点呢,谢谢。
    2
  • 小飞同学
    问两个问题: 1.为啥@Validated注解必须放在类上,不然就校验不住了。 傅哥引入的是hibernate那个么? 2.我的印象中 @Autowired只能按照类型注入,这里有点颠覆认知 那么问题来了,@Resource和@Autowired区别到底是啥?
    3
    2
  • 可乐
    问题: public interface DataService { void deleteStudent(int id); } 这个接口并没有注入bean,为什么可以用autowire去找这个bean呢?
    2
    1
  • Monday
    1、@Priority(value=${number})看源码:值越小优先级越低,可以为负数,若存在两个候选直接抛异常. 2、思考题:不可以,命名方式不能通过
    1
  • 虹炎
    不能做到,因为会报编译错误。studentController.InnerClassDataService; 这一句。
    1
收起评论
显示
设置
留言
20
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部