Spring IOC

0 阅读4分钟

一、什么是 IOC

1. 全称

IOC = Inversion of Control,控制反转,是一种设计思想,Spring IOC 是该思想的落地容器。

2. 传统开发 vs IOC

传统开发(主动创建对象)

业务代码主动 new 依赖,控制权在开发者代码手里:

// 代码自己控制对象创建、依赖管理
UserService service = new UserServiceImpl();
UserDao dao = new UserDaoImpl();
service.setDao(dao);

问题:耦合严重、替换实现类要改代码、难以单元测试。

IOC 控制反转(容器管理对象)

对象创建、依赖装配、生命周期全部交给 IOC 容器,业务代码只使用,不负责创建。 控制权从业务代码反转到容器,因此叫控制反转。

3. DI(依赖注入)——IOC 的实现手段

IOC 是思想,DI(Dependency Injection 依赖注入)是实现 IOC 的方式: 容器自动把对象需要的依赖注入进去,无需手动 new。

二、Spring IOC 容器核心职责

  1. Bean 管理:实例化、缓存单例 Bean
  2. 依赖注入 DI:自动装配属性、构造器、接口依赖
  3. Bean 生命周期管理:初始化、销毁回调
  4. Bean 作用域:singleton /prototype/request /session 等
  5. 配置读取:XML、注解、JavaConfig、注解扫描
  6. AOP 基础支撑:容器管理 Bean 才能生成代理对象

三、IOC 容器两大核心接口

1. BeanFactory(顶层根接口)

最简单容器,懒加载:使用时才实例化 Bean,只提供基础 Bean 获取能力。

BeanFactory factory = new XmlBeanFactory(new FileSystemResource("beans.xml"));
UserService service = (UserService) factory.getBean("userService");

2. ApplicationContext(BeanFactory 子接口,日常开发用)

功能增强容器,项目标准容器,容器启动时立即实例化所有单例 Bean,额外能力:

  • 国际化支持
  • 资源加载(文件 / 类路径)
  • 事件发布监听
  • 注解自动扫描 常用实现类:
  1. ClassPathXmlApplicationContext:类路径读取 XML
  2. FileSystemXmlApplicationContext:磁盘路径 XML
  3. AnnotationConfigApplicationContext:纯注解 / JavaConfig(SpringBoot 默认)
  4. WebApplicationContext:Web 环境容器

四、三种依赖注入 DI 方式

1. 构造器注入(推荐,Spring 官方推荐)

通过构造方法传入依赖,强制依赖不为空,不可变对象:

@Component
public class UserService {
    private final UserDao userDao;
    // 构造注入
    public UserService(UserDao userDao) {
        this.userDao = userDao;
    }
}

2. Setter 注入

无参构造 + set 方法注入,适合可选依赖:

@Component
public class UserService {
    private UserDao userDao;
    @Autowired
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }
}

3. 字段注入(不推荐,仅测试简单使用)

直接在成员变量加 @Autowired,破坏封装,无法做依赖校验:

@Component
public class UserService {
    @Autowired
    private UserDao userDao;
}

五、Bean 定义三种配置方式

1. XML 配置(早期 Spring)

<bean id="userDao" class="com.dao.UserDaoImpl"/>
<bean id="userService" class="com.service.UserService">
    <constructor-arg ref="userDao"/>
</bean>

2. 注解扫描(SSM 主流)

  • @Component / @Service / @Repository / @Controller:标记 Bean
  • @Autowired:自动按类型注入
  • @Qualifier("beanName"):同类型多个 Bean 指定名称
  • @Value("${xxx}"):注入配置文件属性
@Repository
public class UserDaoImpl implements UserDao {}

@Service
public class UserService {
    @Autowired
    private UserDao userDao;
}

3. JavaConfig(SpringBoot 默认,完全替代 XML)

@Configuration 标记配置类,@Bean 手动注册 Bean:

@Configuration
public class SpringConfig {
    @Bean
    public UserDao userDao() {
        return new UserDaoImpl();
    }
    @Bean
    public UserService userService(UserDao userDao) {
        return new UserService(userDao);
    }
}

启动容器:

ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);

六、Bean 五大作用域

  1. singleton(默认) :整个容器仅一个实例,容器创建时初始化
  2. prototype:每次 getBean() 创建新对象,多实例
  3. request:一次 HTTP 请求一个 Bean(Web)
  4. session:一个用户会话一个 Bean(Web)
  5. globalSession:集群 Session(Web)

七、Bean 完整生命周期(IOC 容器执行流程)

  1. 容器读取配置,扫描所有 Bean 定义
  2. 实例化 Bean(调用无参构造)
  3. 填充属性(DI 依赖注入)
  4. 执行 @PostConstruct / InitializingBean 初始化方法
  5. Bean 就绪,可供程序使用
  6. 容器关闭时,执行 @PreDestroy / DisposableBean 销毁方法

八、IOC 核心优势

  1. 解耦:业务代码不依赖具体实现,只依赖抽象接口
  2. 便于单元测试:可轻易 Mock 依赖,无需修改业务代码
  3. 统一管理对象:单例统一管控,减少内存开销
  4. 简化代码:消除大量 new、对象装配样板代码
  5. 为 AOP、事务、缓存等高级功能提供底层支撑

九、IOC 底层核心原理简单概括

  1. 容器通过反射创建 Bean 对象
  2. 反射调用构造 /set 方法完成依赖注入
  3. 用 ConcurrentHashMap 缓存单例 Bean(一级缓存)
  4. 三级缓存解决循环依赖问题(singleton 循环引用)