di是ioc思想的具体落地方式:ioc将对象创建权交给容器,di则由容器在运行时自动将依赖bean注入目标类,如userservice不再new userdao而是接收容器注入的实例;没有di,ioc只是空谈。

直接讲清楚 DI 是 IOC 的落地方式,而不是堆砌注解名称。面试官想听的是你理解“为什么需要注入”,而不是“怎么写@Autowired”。
说清 DI 和 IOC 的关系,一句话定调
IOC 是“把对象创建权交给容器”的设计思想,DI 是实现这个思想的具体手段——容器在运行时把依赖的 Bean 自动塞进目标类里。比如 UserService 不再自己 new UserDao,而是由 Spring 把已创建好的 UserDao 实例注入进来。没有 DI,IOC 就只是空谈。
三种注入方式要对比着说,突出适用场景和隐患
构造器注入:依赖在创建对象时就强制传入,不可变、可测性强,适合必须依赖;
Setter 注入:灵活性高,但可能被多次调用,适合可选依赖或后期修改;
字段注入(@Autowired 直接写在属性上):写起来最省事,但破坏封装、无法做 final 修饰、单元测试难 mock,Spring 官方文档明确不推荐。
Java Maven 项目审查工作流的通用输入处理。当 Java Maven 项目以 ZIP压缩包或 GitLab 仓库 URL 形式提供且需要...时使用。
- 构造器注入能天然规避循环依赖(但注意:它本身会触发循环依赖报错)
- 字段注入在 Lombok 的 @RequiredArgsConstructor 下容易误用,需留意是否真有必要
- 如果接口有多个实现类,@Autowired 配合 @Qualifier 或 @Resource(name = "xxx") 才能精准定位
自动配置和 DI 是怎么联动的
Spring Boot 启动时,通过 @EnableAutoConfiguration 加载大量自动配置类(如 DataSourceAutoConfiguration),这些类内部用 @Bean 方法声明组件,并由 Spring 容器统一管理。其他业务类通过构造器或 Setter 注入这些自动装配的 Bean,整个过程对开发者透明。比如你加了 spring-boot-starter-data-jpa,JPA 相关的 EntityManager、TransactionManager 就会被自动创建并可供注入。
- 自动配置类本身也是 Bean,受条件注解(@ConditionalOnClass、@ConditionalOnMissingBean)控制,避免冲突
- 你写的 @Service 类能注入 DataSource,是因为自动配置已把它注册进容器,DI 才有东西可注
遇到循环依赖别只说“加 @Lazy”,要讲清边界
Spring 默认只解决单例 + Setter/Field 注入下的循环依赖,靠三级缓存(singletonFactories → earlySingletonObjects → singletonObjects)临时暴露早期引用。但以下情况它无能为力:
- 构造器注入的循环依赖:实例化阶段就卡住,无法提前暴露引用
- 原型(@Scope("prototype"))Bean:每次都是新实例,不进缓存,没法复用
- @Async 或 AOP 代理增强后的 Bean:代理对象生成时机可能导致注入失败
真正健壮的做法是重构代码,拆分职责或引入中间层,而不是依赖 @Lazy 治标不治本。










