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回溯算法解决非递减子序列问题(LeetCode 491)的深度解析
java·算法·leetcode
众乐乐_20082 分钟前
Java 后端给前端传Long值,精度丢失的问题与解决
java·前端·状态模式
北辰浮光8 分钟前
[springboot]SSM日期数据转换易见问题
java·spring boot·后端
两点王爷8 分钟前
IDEA中springboot项目中连接docker
spring boot·docker·intellij-idea
木梓辛铭15 分钟前
Spring Cache的详细使用
java·后端·spring
招风的黑耳18 分钟前
Java视频流RTMP/RTSP协议解析与实战代码
java·视频流
邪恶的贝利亚33 分钟前
定时器设计
java·linux·前端
工业互联网专业34 分钟前
基于springboot+vue的机场乘客服务系统
java·vue.js·spring boot·毕业设计·源码·课程设计·机场乘客服务系统
饕餮争锋35 分钟前
WebMvcConfigurer介绍-笔记
java·笔记·servlet
招风的黑耳41 分钟前
Java集合框架详解与使用场景示例
java·开发语言