Spring Boot中的依赖注入是如何工作

Spring Boot 中的依赖注入(Dependency Injection,简称 DI)是通过 Spring 框架的核心机制------控制反转(Inversion of Control,IOC)容器来实现的。Spring Boot 基于 Spring Framework,在应用中自动进行对象的创建、管理、注入等工作,开发者只需要声明依赖关系,Spring 会自动将这些依赖注入到类中。

依赖注入的工作原理

在 Spring Boot 中,依赖注入的核心概念是:通过容器( ApplicationContext)来管理和注入类的依赖。Spring 通过 注解来声明和管理这些依赖。

主要的注解有:

  • @Component / @Service / @Repository / @Controller:这些注解用于标记一个类为 Spring 管理的 Bean。
  • @Autowired:用于标注类中的依赖变量,告诉 Spring 自动注入相应的 Bean。
  • @Configuration 和 @Bean:用于配置类及其方法,生成和管理 Bean。

依赖注入的工作流程

  1. Bean 定义 :通过注解将类标记为 Spring 管理的 Bean(如 @Service,@Component 等)。
  2. 自动注入 :使用 @Autowired 注解将需要的 Bean 注入到类中。Spring Boot 会根据类型自动查找匹配的 Bean 并注入。
  3. 容器管理:Spring 会自动扫描指定的包(通常是启动类所在的包及其子包),根据注解发现类,并把它们放入 IOC 容器中进行管理。
  4. 生命周期管理:Spring 管理这些 Bean 的生命周期,包括实例化、依赖注入、初始化等。

代码案例:Spring Boot 中的依赖注入

1. 创建 Bean 类
java 复制代码
package com.hk.service;

import org.springframework.stereotype.Service;

@Service
public class UserService {
    public String getUserInfo(String userId) {
        return "User的id是: " + userId;
    }
}
  • @Service 注解将 UserService 类标记为一个 Spring 管理的 Bean。Spring Boot 会将 UserService 作为一个 Bean 加入到 Spring 容器中进行管理。
2. 依赖注入到其他类
java 复制代码
package com.hk.controller;

import com.hk.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class UserController {

    private final UserService userService;

    // 通过构造器注入 UserService
    @Autowired
    public UserController(UserService userService) {
        this.userService = userService;
    }

    @GetMapping("/user/{userId}")
    public String getUserInfo(@PathVariable String userId) {
        // 使用注入的 UserService 实例
        return userService.getUserInfo(userId);
    }
}
  • @RestController 注解用于定义一个 REST 控制器,是一个处理 HTTP 请求的组件。
  • @Autowired 注解用于自动注入UserService实例。在上面的代码中,依赖注入是通过构造器进行的。
    • 构造器注入 是推荐的方式,它可以确保依赖关系在对象创建时就已经完全注入。构造器注入具有更高的可测试性和更好的不可变性。
3. 自动注入的其他方式

除了构造器注入,Spring 还支持 字段注入 和 setter 注入。

a. 字段注入
java 复制代码
@RestController
public class UserController {

    @Autowired
    private UserService userService;  // 字段注入

    @GetMapping("/user/{userId}")
    public String getUserInfo(@PathVariable String userId) {
        return userService.getUserInfo(userId);
    }
}
  • 字段注入是将 @Autowired 注解直接放在字段上,Spring 会自动注入对应类型的 Bean。
  • 这种方式代码简洁,但缺点是无法控制依赖注入的顺序,且不容易进行单元测试。
b. Setter 注入
java 复制代码
@RestController
public class UserController {

    private UserService userService;

    @Autowired
    public void setUserService(UserService userService) {
        this.userService = userService;
    }

    @GetMapping("/user/{userId}")
    public String getUserInfo(@PathVariable String userId) {
        return userService.getUserInfo(userId);
    }
}
  • Setter 注入通过 @Autowired 注解标记在 setter 方法上,Spring 会调用这个方法来注入依赖。
  • 适用于某些需要选择性注入的场景,或者对于可选的依赖进行注入。
4. 使用 @Qualifier 注解解决多个 Bean 的冲突

如果有多个类型相同的 Bean,Spring 会根据类型来进行注入,但如果类型不唯一,会抛出 NoUniqueBeanDefinitionException 异常。在这种情况下,我们可以使用 @Qualifier 注解来指定注入哪一个 Bean。

假设我们有两个 UserService 的实现类:

java 复制代码
package com.hk.service;

import org.springframework.stereotype.Service;

@Service("userServiceV1")
public class UserServiceV1 implements UserService {
    public String getUserInfo(String userId) {
        return "User V1 的id是: " + userId;
    }
}

@Service("userServiceV2")
public class UserServiceV2 implements UserService {
    public String getUserInfo(String userId) {
        return "User V2 的id是: " + userId;
    }
}

使用 @Qualifier 来指定注入的 Bean:

java 复制代码
package com.hk.controller;

import com.hk.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class UserController {

    private final UserService userService;

    @Autowired
    public UserController(@Qualifier("userServiceV1") UserService userService) {
        this.userService = userService;
    }

    @GetMapping("/user/{userId}")
    public String getUserInfo(@PathVariable String userId) {
        return userService.getUserInfo(userId);
    }
}
  • 通过 @Qualifier("userServiceV1") 注解,我们指定了要注入 userServiceV1 Bean。
5. @Primary 注解

如果有多个类型相同的 Bean,且不想每次都使用 @Qualifier 来指定注入哪个 Bean,可以使用 @Primary 注解来标记一个优先注入的 Bean。

java 复制代码
package com.hk.service;

import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;

@Service
@Primary
public class UserServiceV1 implements UserService {
    public String getUserInfo(String userId) {
        return "User V1 的id是: " + userId;
    }
}
  • @Primary 注解标记的 Bean 将会是默认注入的 Bean,Spring 会优先选择它进行注入。

总结

在 Spring Boot 中,依赖注入的工作原理是通过 Spring 容器管理对象的生命周期,并将所需的依赖注入到类中。常见的注入方式包括构造器注入、字段注入和 setter 注入。Spring 使用 @Autowired 注解来自动注入依赖,通过 @Component 和其衍生注解(如 @Service,@Repository 等)标记 Bean。还可以通过 @Qualifier 和 @Primary 注解来解决多个 Bean 的冲突问题。

相关推荐
Escalating_xu12 分钟前
【Linux 网络编程】五种 I/O 模型与非阻塞 I/O:从“等数据”到正确处理 EAGAIN
java·linux·网络
程序猿乐锅37 分钟前
万字详解Single-flight(单飞模式)
java·开发语言·分布式·后端·学习·single-flight
Java后端的Ai之路1 小时前
【AIAgent开发】-Agent工具封装成CLI(纯干货!!!)
java·javascript·人工智能·agent·cli
AntsData1 小时前
用 12K+ 条亚马逊评论信号,定位机械键盘下一版该改什么
java·大数据·计算机外设
code2cat1 小时前
【随笔】连续批处理:长短请求怎样在迭代之间补位
java·人工智能·后端·大语言模型·vllm
最强小杰1 小时前
DeepSeek V4 Flash + Codex CLI 接入教程:原生 Responses API 适配,从配置到跑通收藏这篇就够了(2026)
java·前端·python·ai
Flynn Liang2 小时前
Spring AI 2.0 深度解析:ChatClient、Advisor 链与 MCP——Java 工程师的 AI 落地最优解
java·人工智能·spring·大模型·架构设计·spring ai
灿飞2 小时前
Kotlin与Java虚拟机六:基础与类型系统:一切皆对象,但对象有代价
java·kotlin
计算机毕设定制辅导-无忧学长2 小时前
《基于微信小程序健康习惯激励系统设计与实现》
java·spring boot·mysql·微信小程序·uniapp·健康习惯激励系统
掘金者阿豪2 小时前
SQL Server数据迁移完成后,凌晨的数据库告警该怎么查?
前端·后端