Spring依赖注入方式(构造器、Setter、注解)

通俗易懂!Spring 依赖注入(DI)三种方式一次讲透(2025 面试最爱问,背完直接画图秒杀)

一句话记住:

依赖注入就是“我要用别人,不自己 new”,Spring 帮你自动塞进来。
三种方式:构造器注入(最推荐)、Setter 注入(老古董)、注解注入(日常主力 @Autowired)

三种方式对比表(面试必画,一目了然)

注入方式配置方式优点缺点2025 项目推荐度适用场景
构造器注入或 自动(推荐)强制依赖、不可变、便于测试、支持循环依赖参数多时构造器很长★★★★★(大厂标配)所有必填依赖(Service、Repository)
Setter 注入或 @Autowired 于 set 方法可选依赖、灵活改值可被外部改成 null、不安全★★可选依赖、老项目维护
注解注入@Autowired(最常用)代码最少、最爽、支持字段/Setter/构造器容易乱用、可被反射改值★★★★日常开发 90% 场景

1. 构造器注入(2025 最推荐!大厂强制)

为什么最牛?

  • 依赖不可变(final)
  • 对象一出生就完整(避免半初始化)
  • 单元测试超简单(直接 new)
  • Spring Boot 2.6+ 默认优先构造器注入

代码示例(超级简单)

@Service
public class UserService {

    private final UserRepository repository;  // final 强制注入

    // Spring 自动注入(只有一个构造器时,@Autowired 可省略!)
    public UserService(UserRepository repository) {
        this.repository = repository;
    }

    public void save() {
        repository.save();
    }
}

老 XML 方式(了解即可)

<bean id="userService" class="com.example.UserService">
    <constructor-arg ref="userRepository"/>
</bean>

2. Setter 注入(基本没人用了)

@Service
public class OrderService {

    private PaymentService paymentService;

    @Autowired  // 可以加在 set 方法上
    public void setPaymentService(PaymentService paymentService) {
        this.paymentService = paymentService;
    }
}

老 XML

<bean id="orderService" class="com.example.OrderService">
    <property name="paymentService" ref="paymentService"/>
</bean>

3. 注解注入(你天天在用,90% 代码都是它)

三种写法都行(推荐字段注入,代码最少)

@Service
public class ProductService {

    @Autowired              // 最常见!直接写在字段上
    private CategoryService categoryService;

    // 或者写在 Setter 上(和上面一样效果)
    // @Autowired
    // public void setCategoryService(CategoryService categoryService) { ... }

    // 或者写在构造器(最推荐,但代码稍多)
    // private final CategoryService categoryService;
    // @Autowired
    // public ProductService(CategoryService categoryService) { ... }
}

其他常用注解

  • @Resource(JDK 自带,按 name 注入)
  • @Inject(JSR-330 标准,和 @Autowired 差不多)
  • @Value(“${app.name}”) 注入配置值
  • @Qualifier(“xxx”) 解决同类型多个 Bean 冲突

实际项目 2025 真实用法(直接抄)

@RestController
public class UserController {

    private final UserService userService;  // 构造器注入(推荐)

    public UserController(UserService userService) {
        this.userService = userService;
    }

    @Autowired
    private RedisTemplate<String, Object> redis;  // 字段注入(简单场景)

    @GetMapping("/list")
    public List<User> list() {
        return userService.findAll();
    }
}

面试最爱问的 6 个问题 + 标准答案

  1. 三种注入方式的区别?
    答:构造器最安全强制、Setter 最灵活可选、注解最简洁。推荐构造器 + @Autowired。
  2. 为什么大厂都用构造器注入?
    答:依赖不可变、支持 final、避免空指针、便于测试、不支持循环依赖时能提前报错。
  3. @Autowired 可以省略吗?
    答:可以!只有一个构造器时,Spring 自动注入,@Autowired 可不写(Boot 2.6+ 默认)。
  4. 多个相同类型 Bean 怎么选?
    答:用 @Qualifier(“beanName”) 或 @Primary 标记主候选。
  5. 循环依赖用哪种方式会报错?
    答:构造器注入会直接报错(无法解决),字段/Setters 能用三级缓存解决。
  6. @Autowired 是怎么实现的?
    答:AutowiredAnnotationBeanPostProcessor 在 Bean 生命周期的属性填充阶段完成注入。

终极记忆口诀(10 秒背会)

“构造器最牛强制填,Setter 老古董可选,
注解最爽天天见,字段构造随便选,
大厂只爱构造器,代码干净又安全!”

一张图记住(面试 30 秒画完)

构造器注入(推荐★★★★★)
   ↓
注解注入(日常★★★★)
   ↓
Setter 注入(过时★★)

背完这张表 + 示例代码 + 口诀,
面试官问“Spring 依赖注入有几种方式”,你 1 分钟画表 + 甩代码,直接满分!
现在你已经彻底掌握 DI 了,下一个目标:自己写一个循环依赖案例试试!冲!

文章已创建 3040

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部