“同学,能不能讲讲你对Spring的依赖注入的理解?”
这句话你是不是在面试中听到过很多次?
没错,我上周刚经历了一场让人汗毛直立的Java社招面试,结果卡在了—— “什么是Spring的依赖注入” 这道看似简单、实则深水的大题上。
那天的我,穿着干净的衬衫,满脸自信地坐在某十八线大厂的面试间里,结果刚坐下不到十分钟,面试官微微一笑,“聊聊Spring的IOC吧。”
我心想,这不是入门题嘛?然后啪啦啪啦讲了一通:
“Spring的IOC容器是控制反转的体现,它可以帮助我们自动装配Bean,实现解耦……”
结果刚说完,面试官一句话把我打回原形:
“你说了控制反转,那依赖注入是什么?它跟IOC一样吗?”
我当场愣住,冷汗冒出来。接下来半小时,成了灵魂拷问之旅……
小故事:依赖注入是怎么打脸我的?
说来惭愧,虽然我平时工作中天天写@Autowired,但真让我深讲这个注解背后的原理、IOC容器的创建流程、依赖注入的类型……我的脑子就变成了泡面。
于是我带着这道题和我的残余自尊,回家开了一晚上的debug,终于理清楚了“依赖注入”的底层逻辑。
今天,我就以这个故事为契机,把我踩过的坑和学到的精华统统分享出来!
一句话解释:依赖注入是控制反转的一种实现方式!
- 控制反转(Inversion of Control, IOC) 是一种设计思想。
- 依赖注入(Dependency Injection, DI) 是实现控制反转的具体技术手段。
很多小伙伴容易把IOC和DI混为一谈,这其实是“概念”与“实现”的关系。
通俗点讲:
- IOC就像是“你把控制权交出去”,以前你new对象,现在框架帮你new;
- 而依赖注入,就是Spring用来帮你把这些对象装配好的一种方式。
它们之间的关系就像:
“我决定不自己做饭了”(IOC) → “我点了外卖,外卖小哥送到家里”(DI)
再讲清楚点,什么是依赖注入?
来看个简单例子。
以前我们写代码可能是这样的:
但在Spring里,我们更推荐这样写:
这就是依赖注入的体现:
- UserService依赖于UserRepository;
- 这个依赖关系不是由UserService主动创建(new),而是Spring框架在后台给它注入的。
Spring是怎么实现依赖注入的?
我们来扒一扒Spring的底层:
1. Bean定义
Spring启动时会扫描你的配置类或XML文件,找到所有的Bean定义,比如:
或者传统的XML配置:
2. 创建对象(实例化)
Spring会通过反射创建这些类的对象。注意:这一步还没有注入依赖!
3. 注入依赖
接下来,Spring会根据注解或者XML配置,把其他依赖注入进去,比如:
- 属性注入(最常见的,@Autowired)
- 构造器注入(推荐)
- Setter注入(老旧代码中较多)
比如构造器注入:
Spring会自动找到PaymentService的Bean,把它注入到OrderService中。
面试中怎么回答“Spring的依赖注入”?
我整理了一份面试回答模板,分享给你:
面试高能回答版:
在Spring中,依赖注入(Dependency Injection)是一种实现控制反转(IOC)的技术手段。通过将对象所依赖的资源(如其他Bean)交由Spring容器管理,从而解耦组件之间的关系,提升系统的可维护性和扩展性。
Spring主要支持三种依赖注入方式:
构造器注入(推荐方式,适用于必填依赖,利于单元测试)
Setter方法注入(适用于可选依赖)
字段注入(使用@Autowired注解,最简便,但不利于测试)
Spring容器在初始化时,会扫描并注册所有的Bean定义,然后根据依赖关系完成注入,依赖查找使用的是类型优先的方式,必要时可结合@Qualifier、@Primary来解决冲突。
延伸面试问题合集
你以为答完依赖注入就完了?不,真正可怕的是面试官的后续追问!
以下问题,我统统经历过:
- @Autowired是按什么规则注入的?按类型还是按名称?
- 如果多个同类型Bean,Spring如何决定注入哪一个?
- @Autowired和@Resource的区别是什么?
- 构造器注入和字段注入优劣对比?
- Spring中依赖注入的底层原理是如何实现的?(谈反射、BeanFactory、DefaultListableBeanFactory)
- Spring Boot如何自动完成依赖注入的?
- 如何解决循环依赖的问题?
所以,你要做的不是只懂@Autowired怎么写,而是要“知其然,知其所以然”。
实战演练:自己动手写个简易版IOC容器
要真正理解依赖注入,强烈推荐你写一遍“迷你Spring”。
看个极简例子:
然后:
这就是最简单的“手动IOC”模型!
你能从这个实验中感受到依赖注入的本质:创建对象 → 注册到容器 → 从容器获取 → 注入使用。
总结一下
最后小米想说
其实,“依赖注入”并不难,但难在我们太容易陷入“写得出来就懂了”的错觉。真正深入理解它,需要我们了解设计理念、底层实现、使用场景、注解原理,甚至再往下看Spring源码中的AutowiredAnnotationBeanPostProcessor。
不要怕复杂,面试就是在拆你会不会把日常代码写得清楚,也能讲得清楚。
我31岁了,还在社招面试中被“依赖注入”拷打,我知道这很痛,但也很有价值。
只要我们继续学习和输出,技术这条路永远都能走下去!
END
如果你也在准备面试,不妨点个“在看”支持一下;留言说说你遇到过的最刁钻面试题,我来陪你一起解析!
我们下篇文章见~
我是小米,一个喜欢分享技术的31岁程序员。如果你喜欢我的文章,欢迎关注我的微信公众号“软件求生”,获取更多技术干货!