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 的冲突问题。

相关推荐
宇宙李1 分钟前
微服务中熔断和降级的区别,具体使用场景有哪些?
java·数据库·微服务
BinaryBardC9 分钟前
Objective-C语言的网络编程
开发语言·后端·golang
鹿屿二向箔12 分钟前
一个基于Spring Boot的简单网吧管理系统
spring boot·后端·python
java熊猫14 分钟前
Clojure语言的多线程编程
开发语言·后端·golang
连胜优佳18 分钟前
20、javase-API.容器
java·开发语言
云端 架构师38 分钟前
Elixir语言的语法糖
开发语言·后端·golang
leo_hush1 小时前
【Flink】flink或java异常日志输出不完整问题解决
java·大数据·flink
PieroPc1 小时前
做一个 简单的Django 《股票自选助手》显示 用akshare 库(A股数据获取)
后端·python·django
binqian1 小时前
【Docker】安装registry本地镜像库,开启Https功能
java·docker·https
计算机-秋大田1 小时前
基于Spring Boot的扶贫助农系统设计与实现(LW+页码+讲解)
java·vue.js·spring boot·后端·课程设计