springboot ioc 控制反转入门与实战

Spring Boot3 IOC 项目地址

https://gitee.com/supervol/loong-springboot-study

(记得给个start,感谢)

IOC 概述

在 Spring Boot 3 中,IOC(Inversion of Control,控制反转)是核心思想之一,它彻底改变了传统 Java 开发中对象创建和依赖管理的方式,极大地降低了代码耦合度,提升了系统的可维护性和扩展性。

IOC 核心概念

IOC 的本质是将对象的创建权、依赖关系的管理交给 Spring 容器,而非由开发者在代码中手动 new 对象或维护依赖。这种 "反转" 体现在:

  • 传统开发:开发者主动控制对象创建(如UserService service = new UserService())和依赖注入(如service.setDao(new UserDao()))。
  • IOC 模式:Spring 容器负责创建对象(Bean),并根据配置自动将依赖对象 "注入" 到目标对象中,开发者只需声明 "需要什么",无需关心 "如何获取"。

IOC 与 DI 的关系

DI(Dependency Injection,依赖注入)是 IOC 的具体实现方式

  • IOC 是思想:强调 "反转控制"(将对象管理权交给容器)。
  • DI 是手段:容器通过构造器、setter 方法等方式,将依赖对象 "注入" 到目标对象中,完成依赖关系绑定。

IOC 示例

请参考项目地址中 springboot-ioc/springboot-ioc-demo 模块代码。

IOC 使用

Spring Boot 3 基于 Spring Framework 6,简化了 IOC 容器的配置(无需 XML,全注解驱动),核心步骤如下:

定义 Bean

让容器管理对象,Spring 通过注解识别需要管理的对象(Bean),常用注解:

  • @Component:通用注解,标识一个类为 Spring 管理的 Bean(适用于普通组件)。
  • @Service:标注业务逻辑层(Service)的 Bean(语义化注解,本质是@Component)。
  • @Controller:标注控制层(MVC 中的 Controller)的 Bean。
  • @Repository:标注数据访问层(DAO)的 Bean,还会自动处理数据库操作异常。

示例:定义 Service 层 Bean

复制代码
// 业务逻辑层,@Service标识为Spring管理的Bean
@Service
public class UserService {
    // 后续通过DI注入依赖
    private final UserDao userDao;

    // 构造器注入(推荐)
    public UserService(UserDao userDao) {
        this.userDao = userDao;
    }

    public String getUserInfo() {
        return userDao.queryUser();
    }
}

示例:定义 DAO 层 Bean

复制代码
// 数据访问层,@Repository标识为Spring管理的Bean
@Repository
public class UserDao {
    public String queryUser() {
        return "用户信息:张三";
    }
}

依赖注入(DI)

容器自动注入依赖,Spring 提供多种注入方式,推荐构造器注入(更符合单一职责,且避免空指针问题)。

(1)构造器注入(推荐)

通过类的构造方法,容器自动传入依赖的 Bean(如上面UserService中注入UserDao)。

(2)Setter 方法注入

通过 setter 方法注入依赖,需配合@Autowired注解:

复制代码
@Service
public class UserService {
    private UserDao userDao;

    // Setter注入
    @Autowired
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }
}

(3)字段注入(不推荐)

直接在字段上使用@Autowired注入,缺点是无法通过构造器保证依赖非空,且不利于单元测试:

复制代码
@Service
public class UserService {
    // 字段注入(不推荐)
    @Autowired
    private UserDao userDao;
}

启动容器并使用 Bean

Spring Boot 通过@SpringBootApplication注解启动容器,该注解包含:

  • @ComponentScan:自动扫描当前包及子包下的@Component(含@Service@Controller等)注解类,将其注册为 Bean。

示例:启动类与使用 Bean

复制代码
// 启动类,@SpringBootApplication标识Spring Boot应用入口
@SpringBootApplication
public class IocDemoApplication {
    public static void main(String[] args) {
        // 启动Spring容器,返回ApplicationContext(容器上下文)
        ApplicationContext context = SpringApplication.run(IocDemoApplication.class, args);

        // 从容器中获取UserService Bean
        UserService userService = context.getBean(UserService.class);

        // 调用Bean的方法(依赖已由容器自动注入)
        System.out.println(userService.getUserInfo()); // 输出:用户信息:张三
    }
}

自定义 Bean

非 @Component 注解类,如果需要将第三方类(如RedisTemplate)或未加@Component的类注册为 Bean,可通过@Configuration+@Bean实现:

复制代码
// 配置类,@Configuration标识为配置类
@Configuration
public class CustomConfig {

    // @Bean:将方法返回值注册为Spring容器中的Bean,默认名称为方法名
    @Bean
    public RedisUtil redisUtil() {
        return new RedisUtil(); // 假设RedisUtil是第三方工具类
    }
}

// 使用自定义Bean
@Service
public class OrderService {
    private final RedisUtil redisUtil;

    // 注入自定义的RedisUtil Bean
    public OrderService(RedisUtil redisUtil) {
        this.redisUtil = redisUtil;
    }
}

Bean 的作用域

默认情况下,Spring 容器中的 Bean 是单例(singleton) (整个容器中只有一个实例)。可通过@Scope指定其他作用域:

  • @Scope("prototype"):多例,每次获取 Bean 时创建新实例。
  • @Scope("request"):Web 环境中,每个请求对应一个实例。
  • @Scope("session"):Web 环境中,每个会话对应一个实例。

示例:多例 Bean

复制代码
@Service
@Scope("prototype") // 多例模式
public class CartService {
    // ...
}

IOC 的优势

  1. 解耦 :对象创建与依赖管理交给容器,避免硬编码依赖(如new UserService(new UserDao()))。
  2. 可维护性:集中管理 Bean 的生命周期和依赖,修改依赖只需调整配置。
  3. 可测试性:便于替换依赖(如测试时用 Mock 对象替换真实 DAO)。
  4. 灵活性:通过作用域、懒加载等配置,灵活控制 Bean 的创建时机和生命周期。

总结

Spring Boot 3 的 IOC 通过注解驱动简化了 Bean 的定义和依赖管理,核心是 "将控制权交给容器"。实际开发中,推荐使用@Service@Repository等语义化注解定义 Bean,通过构造器注入 管理依赖,配合@Configuration+@Bean处理自定义 Bean,充分发挥 IOC 的解耦优势。

相关推荐
deepwater_zone2 小时前
Spring 微服务
spring·微服务
叫我阿柒啊3 小时前
从Java全栈到前端框架:一位程序员的实战之路
java·spring boot·微服务·消息队列·vue3·前端开发·后端开发
mqiqe3 小时前
架构-亿级流量性能调优实践
java·架构
中国胖子风清扬3 小时前
Rust 序列化技术全解析:从基础到实战
开发语言·c++·spring boot·vscode·后端·中间件·rust
野犬寒鸦4 小时前
力扣hot100:旋转图像(48)(详细图解以及核心思路剖析)
java·数据结构·后端·算法·leetcode
七夜zippoe4 小时前
AI+Java 守护你的钱袋子!金融领域的智能风控与极速交易
java·人工智能·金融
岁忧4 小时前
(LeetCode 面试经典 150 题) 200. 岛屿数量(深度优先搜索dfs || 广度优先搜索bfs)
java·c++·leetcode·面试·go·深度优先
liliangcsdn5 小时前
结合prompt分析NodeRAG的build过程
java·服务器·人工智能·数据分析·知识图谱
黑色的山岗在沉睡5 小时前
LeetCode 189. 轮转数组
java·算法·leetcode