首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >深入 Spring IoC 容器底层:从原理到实战,一文讲透控制反转的核心逻辑

深入 Spring IoC 容器底层:从原理到实战,一文讲透控制反转的核心逻辑

作者头像
果酱带你啃java
发布2026-04-14 14:58:15
发布2026-04-14 14:58:15
490
举报

1. 引言

控制反转(Inversion of Control,IoC)是Spring框架的核心思想之一,它将对象的创建、依赖关系的管理从代码中剥离,交给Spring容器统一处理,极大降低了组件间的耦合度,提升了代码的可维护性和可扩展性。本文将从底层原理、核心流程、实战案例三个维度,全面解析Spring IoC容器的实现机制。

2. Spring IoC容器的核心架构

Spring IoC容器主要分为两个层次:基础容器BeanFactory和高级容器ApplicationContext

2.1 BeanFactory

BeanFactory是Spring IoC容器的最底层接口,定义了容器的基本行为,如Bean的获取、类型判断等。它采用懒加载机制,只有在获取Bean时才会进行实例化和初始化,适合资源受限的场景。

2.2 ApplicationContext

ApplicationContext继承自BeanFactory,是更高级的容器实现,除了包含BeanFactory的所有功能外,还提供了事件发布、国际化、资源加载等企业级特性。它默认采用预加载机制,在容器启动时就完成单例Bean的实例化和初始化,适合大多数企业应用场景。

3. IoC容器的初始化流程

Spring IoC容器的初始化流程是一个复杂但有序的过程,主要包含以下步骤:

4. Bean的生命周期

Bean的生命周期是Spring IoC容器的核心内容,主要分为实例化、属性填充、初始化、销毁四个阶段:

4.1 实例化

Spring容器调用Bean的构造函数创建Bean实例,此时Bean只是一个“空壳”,属性尚未填充。

4.2 属性填充

Spring容器通过反射机制,将Bean的依赖关系注入到对应的属性中,支持构造器注入、Setter注入等方式。

4.3 初始化

初始化阶段是Bean功能完善的关键步骤,主要包含以下流程:

  1. 若Bean实现了BeanNameAware接口,容器调用setBeanName方法设置Bean的名称;
  2. 若Bean实现了BeanClassLoaderAware接口,容器调用setBeanClassLoader方法设置类加载器;
  3. 若Bean实现了BeanFactoryAware接口,容器调用setBeanFactory方法设置BeanFactory;
  4. 若Bean实现了ApplicationContextAware接口,容器调用setApplicationContext方法设置ApplicationContext;
  5. 容器调用BeanPostProcessorpostProcessBeforeInitialization方法进行前置处理;
  6. 若Bean实现了InitializingBean接口,容器调用afterPropertiesSet方法;
  7. 容器调用Bean的自定义初始化方法(如@PostConstruct注解标注的方法或XML配置的init-method);
  8. 容器调用BeanPostProcessorpostProcessAfterInitialization方法进行后置处理,此时Bean才真正准备就绪。

4.4 销毁

当容器关闭时,Bean进入销毁阶段:

  1. 若Bean实现了DisposableBean接口,容器调用destroy方法;
  2. 容器调用Bean的自定义销毁方法(如@PreDestroy注解标注的方法或XML配置的destroy-method)。

5. 核心组件解析

5.1 BeanDefinition

BeanDefinition是Spring IoC容器的核心数据结构,用于描述Bean的元数据信息,包括Bean的类名、作用域、依赖关系、初始化方法、销毁方法等。Spring容器根据BeanDefinition来创建和管理Bean。

5.2 BeanDefinitionReader

BeanDefinitionReader负责读取配置元数据(如XML文件、注解、Java配置类),并将其解析为BeanDefinition对象,注册到BeanDefinitionRegistry中。常见的实现类有XmlBeanDefinitionReader(读取XML配置)、AnnotatedBeanDefinitionReader(读取注解配置)等。

5.3 BeanWrapper

BeanWrapper是Spring提供的Bean包装器,封装了Bean实例,提供了属性访问、类型转换等功能。Spring容器通过BeanWrapper来完成Bean的属性填充。

6. 实战案例

6.1 项目环境

  • JDK:17
  • Spring Boot:3.2.4
  • MyBatis-Plus:3.5.6
  • MySQL:8.0
  • Lombok:1.18.32
  • Fastjson2:2.0.47
  • Springdoc:2.3.0

6.2 Maven依赖

代码语言:javascript
复制
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>3.2.4</version>
    <relativePath/>
</parent>
<groupId>com.jam</groupId>
<artifactId>ioc-demo</artifactId>
<version>1.0.0</version>
<name>ioc-demo</name>
<description>Spring IoC Demo</description>
<properties>
    <java.version>17</java.version>
    <mybatis-plus.version>3.5.6</mybatis-plus.version>
    <fastjson2.version>2.0.47</fastjson2.version>
    <springdoc.version>2.3.0</springdoc.version>
</properties>
<dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-validation</artifactId>
    </dependency>
    <dependency>
      <groupId>com.baomidou</groupId>
      <artifactId>mybatis-plus-spring-boot3-starter</artifactId>
      <version>${mybatis-plus.version}</version>
    </dependency>
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>8.0.33</version>
    </dependency>
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <version>1.18.32</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>com.alibaba.fastjson2</groupId>
      <artifactId>fastjson2</artifactId>
      <version>${fastjson2.version}</version>
    </dependency>
    <dependency>
      <groupId>org.springdoc</groupId>
      <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
      <version>${springdoc.version}</version>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <scope>test</scope>
    </dependency>
</dependencies>
<build>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
        <configuration>
          <excludes>
            <exclude>
              <groupId>org.projectlombok</groupId>
              <artifactId>lombok</artifactId>
            </exclude>
          </excludes>
        </configuration>
      </plugin>
    </plugins>
</build>
</project>

6.3 配置文件

代码语言:javascript
复制
spring:
  datasource:
    driver-class-name:com.mysql.cj.jdbc.Driver
    url:jdbc:mysql://localhost:3306/ioc_demo?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&useSSL=false
    username:root
    password:root
application:
    name:ioc-demo
mybatis-plus:
configuration:
    map-underscore-to-camel-case:true
    log-impl:org.apache.ibatis.logging.stdout.StdOutImpl
global-config:
    db-config:
      id-type:auto
      table-underline:true
springdoc:
api-docs:
    path:/v3/api-docs
swagger-ui:
    path:/swagger-ui.html
    enabled:true

6.4 数据库脚本

代码语言:javascript
复制
CREATE DATABASEIFNOTEXISTS ioc_demo DEFAULTCHARACTERSET utf8mb4 COLLATE utf8mb4_general_ci;
USE ioc_demo;
CREATETABLEIFNOTEXISTSuser (
    idBIGINT AUTO_INCREMENT PRIMARY KEYCOMMENT'主键ID',
    username VARCHAR(50) NOTNULLCOMMENT'用户名',
    passwordVARCHAR(100) NOTNULLCOMMENT'密码',
    email VARCHAR(100) COMMENT'邮箱',
    create_time DATETIME DEFAULTCURRENT_TIMESTAMPCOMMENT'创建时间',
    update_time DATETIME DEFAULTCURRENT_TIMESTAMPONUPDATECURRENT_TIMESTAMPCOMMENT'更新时间'
) ENGINE=InnoDBDEFAULTCHARSET=utf8mb4 COMMENT='用户表';

6.5 实体类

代码语言:javascript
复制
package com.jam.demo.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
 * 用户实体类
 * @author ken
 * @since 2026-03-05
 */
@Data
@TableName("user")
@Schema(description = "用户实体")
publicclass User implements Serializable {
    privatestaticfinallong serialVersionUID = 1L;
    /**
     * 主键ID
     */
    @TableId(type = IdType.AUTO)
    @Schema(description = "主键ID")
    private Long id;
    /**
     * 用户名
     */
    @NotBlank(message = "用户名不能为空")
    @Schema(description = "用户名", required = true)
    private String username;
    /**
     * 密码
     */
    @NotBlank(message = "密码不能为空")
    @Schema(description = "密码", required = true)
    private String password;
    /**
     * 邮箱
     */
    @Email(message = "邮箱格式不正确")
    @Schema(description = "邮箱")
    private String email;
    /**
     * 创建时间
     */
    @Schema(description = "创建时间")
    private LocalDateTime createTime;
    /**
     * 更新时间
     */
    @Schema(description = "更新时间")
    private LocalDateTime updateTime;
}

6.6 Mapper接口

代码语言:javascript
复制
package com.jam.demo.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.jam.demo.entity.User;
import org.apache.ibatis.annotations.Mapper;
/**
 * 用户Mapper接口
 * @author ken
 * @since 2026-03-05
 */
@Mapper
public interface UserMapper extends BaseMapper<User> {
}

6.7 Service接口

代码语言:javascript
复制
package com.jam.demo.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.jam.demo.entity.User;
/**
 * 用户Service接口
 * @author ken
 * @since 2026-03-05
 */
public interface UserService extends IService<User> {
    /**
     * 根据用户名查询用户
     * @param username 用户名
     * @return 用户信息
     */
    User getUserByUsername(String username);
}

6.8 Service实现类

代码语言:javascript
复制
package com.jam.demo.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jam.demo.entity.User;
import com.jam.demo.mapper.UserMapper;
import com.jam.demo.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
/**
 * 用户Service实现类
 * @author ken
 * @since 2026-03-05
 */
@Slf4j
@Service
publicclass UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
    @Override
    public User getUserByUsername(String username) {
        if (!StringUtils.hasText(username)) {
            log.warn("查询用户失败,用户名为空");
            returnnull;
        }
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getUsername, username);
        User user = this.getOne(queryWrapper);
        if (ObjectUtils.isEmpty(user)) {
            log.info("未找到用户,用户名:{}", username);
        }
        return user;
    }
}

6.9 Controller类

代码语言:javascript
复制
package com.jam.demo.controller;
import com.jam.demo.entity.User;
import com.jam.demo.service.UserService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
 * 用户Controller
 * @author ken
 * @since 2026-03-05
 */
@Slf4j
@RestController
@RequestMapping("/user")
@Tag(name = "用户管理", description = "用户相关接口")
publicclass UserController {
    privatefinal UserService userService;
    /**
     * 构造器注入UserService
     * @param userService 用户Service
     */
    public UserController(UserService userService) {
        this.userService = userService;
    }
    /**
     * 新增用户
     * @param user 用户信息
     * @return 新增结果
     */
    @PostMapping("/add")
    @Operation(summary = "新增用户", description = "新增一个用户")
    public String addUser(@Valid @RequestBody User user) {
        boolean success = userService.save(user);
        if (success) {
            log.info("新增用户成功,用户信息:{}", user);
            return"新增成功";
        } else {
            log.error("新增用户失败,用户信息:{}", user);
            return"新增失败";
        }
    }
    /**
     * 根据ID查询用户
     * @param id 用户ID
     * @return 用户信息
     */
    @GetMapping("/get/{id}")
    @Operation(summary = "查询用户", description = "根据ID查询用户")
    public User getUserById(@Parameter(description = "用户ID", required = true) @PathVariable Long id) {
        return userService.getById(id);
    }
    /**
     * 查询所有用户
     * @return 用户列表
     */
    @GetMapping("/list")
    @Operation(summary = "查询用户列表", description = "查询所有用户")
    public List<User> getUserList() {
        List<User> userList = userService.list();
        if (CollectionUtils.isEmpty(userList)) {
            log.info("用户列表为空");
        }
        return userList;
    }
    /**
     * 根据用户名查询用户
     * @param username 用户名
     * @return 用户信息
     */
    @GetMapping("/getByUsername")
    @Operation(summary = "根据用户名查询用户", description = "根据用户名查询用户")
    public User getUserByUsername(@Parameter(description = "用户名", required = true) @RequestParam String username) {
        return userService.getUserByUsername(username);
    }
}

6.10 启动类

代码语言:javascript
复制
package com.jam.demo;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
 * 启动类
 * @author ken
 * @since 2026-03-05
 */
@SpringBootApplication
@MapperScan("com.jam.demo.mapper")
public class IocDemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(IocDemoApplication.class, args);
    }
}

6.11 案例解析

在本案例中,Spring IoC容器的作用体现在以下几个方面:

  1. Bean的管理:通过@Service@RestController@Mapper等注解,将UserServiceImplUserControllerUserMapper等类注册为Spring容器中的Bean;
  2. 依赖注入:通过构造器注入的方式,将UserService注入到UserController中,将UserMapper注入到UserServiceImpl中,实现了组件间的解耦;
  3. 生命周期管理:Spring容器负责Bean的实例化、属性填充、初始化和销毁,开发者只需关注业务逻辑的实现。

7. 常见问题与最佳实践

7.1 依赖注入的方式

Spring支持三种依赖注入方式:

  1. 构造器注入(推荐):通过构造函数注入依赖,保证依赖不可变,且更容易进行单元测试;
  2. Setter注入:通过Setter方法注入依赖,适合可选依赖的注入;
  3. 字段注入:通过@Autowired注解直接注入字段,代码简洁但不利于测试和依赖的不可变性,不推荐使用。

7.2 循环依赖

循环依赖是指两个或多个Bean之间相互依赖的情况,Spring容器通过三级缓存机制解决了单例Bean的循环依赖问题。但对于原型Bean的循环依赖,Spring容器无法解决,会抛出异常。

7.3 Bean的作用域

Spring支持以下几种Bean的作用域:

  1. singleton(默认):单例模式,容器中只有一个Bean实例;
  2. prototype:原型模式,每次获取Bean时都会创建一个新的实例;
  3. request:请求作用域,每次HTTP请求都会创建一个新的Bean实例,仅在Web应用中有效;
  4. session:会话作用域,每个HTTP会话都会创建一个新的Bean实例,仅在Web应用中有效;
  5. application:应用作用域,整个Web应用生命周期内只有一个Bean实例,仅在Web应用中有效。

8. 总结

Spring IoC容器是Spring框架的核心,通过控制反转和依赖注入,实现了组件间的解耦,提升了代码的可维护性和可扩展性。本文从底层原理、核心流程、实战案例三个维度,全面解析了Spring IoC容器的实现机制,希望能帮助读者更好地理解和使用Spring框架。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2026-03-09,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 果酱带你啃java 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 引言
  • 2. Spring IoC容器的核心架构
    • 2.1 BeanFactory
    • 2.2 ApplicationContext
  • 3. IoC容器的初始化流程
  • 4. Bean的生命周期
    • 4.1 实例化
    • 4.2 属性填充
    • 4.3 初始化
    • 4.4 销毁
  • 5. 核心组件解析
    • 5.1 BeanDefinition
    • 5.2 BeanDefinitionReader
    • 5.3 BeanWrapper
  • 6. 实战案例
    • 6.1 项目环境
    • 6.2 Maven依赖
    • 6.3 配置文件
    • 6.4 数据库脚本
    • 6.5 实体类
    • 6.6 Mapper接口
    • 6.7 Service接口
    • 6.8 Service实现类
    • 6.9 Controller类
    • 6.10 启动类
    • 6.11 案例解析
  • 7. 常见问题与最佳实践
    • 7.1 依赖注入的方式
    • 7.2 循环依赖
    • 7.3 Bean的作用域
  • 8. 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档