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 的解耦优势。

相关推荐
青草地溪水旁16 分钟前
设计模式(C++)详解——迭代器模式(2)
java·c++·设计模式·迭代器模式
9号达人18 分钟前
Java18 新特性详解与实践
java·后端·面试
我不是混子24 分钟前
java浮点数精度问题及解决方案
java·后端
花心蝴蝶.42 分钟前
Java 中的代理模式
java·开发语言·代理模式
舒克起飞了1 小时前
设计模式——单例模式
java·单例模式·设计模式
Java&Develop1 小时前
GitLab-如何基于现有项目仓库,复制出新的项目仓库
java
一只乔哇噻1 小时前
java后端工程师进修ing(研一版‖day49)
java·开发语言
稻草猫.1 小时前
Java线程安全:volatile与wait/notify详解
java·后端·idea
无敌最俊朗@2 小时前
MQTT 关键特性详解
java·前端·物联网
JAVA学习通2 小时前
微服务项目->在线oj系统(Java-Spring)----[前端]
java·开发语言·前端