Spring IoC 详解

发布于:2025-03-10 ⋅ 阅读:(7) ⋅ 点赞:(0)

IoC 简介

IoC 是什么

IoC控制反转(Inversion of Control),也被称为依赖倒置原则,是设计模式六大原则之一。其核心思想是程序应依赖抽象接口,而非具体实现,从而降低代码间的耦合度。

IoC 的实现方式包括两种:

  • 依赖注入(DI):不通过类内部直接创建依赖对象,而是将外部创建好的依赖对象通过构造函数或参数传递给类使用。
  • 依赖查找:受控对象通过容器 API 查找所需资源和协作对象。

理解 IoC 的关键在于两点:

  1. 谁控制谁,控制什么:传统编程中,对象由程序主动创建;而 IoC 中,对象由容器控制创建,容器负责管理外部资源获取。
  2. 为何反转,哪些方面反转:传统方式是程序主动获取依赖对象(正转),而 IoC 中容器负责创建并注入依赖对象(反转),依赖对象的获取方式发生了反转。

IoC 的作用

IoC 是一种编程思想,而非具体技术,作为面向对象编程的重要法则,它指导设计松耦合的程序。传统方式中,类内部主动创建依赖对象导致高耦合,难以测试;IoC 将对象的创建和查找交由容器管理,使对象间松散耦合,便于测试和复用,提升程序体系结构的灵活性。IoC 体现了“主从换位”思想,应用程序从主动获取资源变为被动接受容器注入,符合“好莱坞法则”:别找我们,我们找你。

IoC 与 DI

IoC 和依赖注入(DI)是从不同角度描述同一概念。IoC 强调控制权的反转,而 DI 更明确地指出依赖对象由容器注入。2004 年,Martin Fowler 提出“依赖注入”这一术语,以更清晰地表达这一过程。

IoC 容器

IoC 容器是具备依赖注入功能的容器,负责实例化、定位、配置应用程序中的对象并管理其依赖关系。在 Spring 中,BeanFactory 是 IoC 容器的基础实现,通过配置文件(如 XML、注解或 Java 代码)定义对象的元数据,容器据此完成对象的组装。

Bean

由 IoC 容器管理的对象称为 Bean。Bean 是容器初始化、装配和管理的对象,其定义通过配置元数据(如 BeanDefinition)指定,描述如何实例化和组装。

Spring IoC

Spring IoC 容器通过构造函数参数、工厂方法参数或属性设置定义 Bean 的依赖关系,创建时由容器注入这些依赖。这一过程是对象主动控制依赖的反转,因此称为控制反转。核心包 org.springframework.beansorg.springframework.context 提供了 IoC 容器的基础支持。

IoC 容器

Spring 提供两种 IoC 容器:

  • BeanFactory:基础 IoC 容器,提供配置框架和基本功能。
  • ApplicationContextBeanFactory 的子接口,扩展了国际化、资源访问、事件机制等功能,适用于大多数场景。

实际开发中,推荐使用 ApplicationContext,因其功能更丰富。ApplicationContext 接口负责实例化、配置和组装 Bean,通过配置元数据(XML、注解或 Java 代码)获取指令。

常见实现包括:

  • ClassPathXmlApplicationContext:从类路径加载配置。
  • FileSystemXmlApplicationContext:从文件系统加载配置。

使用 IoC 容器的步骤包括:

  1. 配置元数据:定义容器如何初始化和管理 Bean。
  2. 实例化容器:容器解析元数据,生成 BeanDefinition 并完成 Bean 的实例化与组装。
  3. 使用容器:客户端通过容器获取所需 Bean。

配置元数据

配置元数据描述 Bean 的属性和依赖,可通过以下方式实现:

  • XML 配置:传统方式,使用 <bean> 元素定义。
  • 注解配置:Spring 2.5 引入,通过注解简化配置。
  • Java 配置:Spring 3.0 引入,使用 Java 代码定义。

实例化容器

通过指定资源路径(如 XML 文件)实例化 ApplicationContext,例如:

ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");

支持通过多个 XML 文件分层定义 Bean,使用 <import/> 元素组合:

<beans>
    <import resource="services.xml"/>
    <bean id="bean1" class="..."/>
</beans>

使用容器

通过 getBean 方法获取 Bean 实例:

ApplicationContext context = new ClassPathXmlApplicationContext("services.xml");
PetStoreService service = context.getBean("petStore", PetStoreService.class);

IoC 配置元数据

XML 配置

XML 配置是 Spring 的传统方式,基本结构如下:

<beans>
    <bean id="bean1" class="..."/>
    <alias alias="bean3" name="bean2"/>
    <import resource="resource.xml"/>
</beans>
  • <bean> 定义 Bean,id 为唯一标识,class 指定类名。
  • <alias> 设置别名。
  • <import> 导入其他配置文件。

实例化方式:

ApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"services.xml", "daos.xml"});

注解配置

Spring 2.5 引入注解配置,需在 XML 中启用:

<context:annotation-config/>

常用注解包括:

  • @Required:修饰 setter 方法,确保属性在 XML 中配置。
  • @Autowired:修饰属性、setter 或构造函数,按类型自动注入。
  • @Qualifier:与 @Autowired 配合,按名称指定 Bean。
  • @Resource:按名称注入,支持 JSP 250 标准。
  • @PostConstruct@PreDestroy:定义生命周期方法。
  • @Inject:Spring 3.0 支持的 JSR 330 注解,功能类似 @Autowired

Java 配置

Spring 3.0 引入 Java 配置,使用 @Configuration@Bean 注解:

@Configuration
public class AppConfig {
    @Bean
    public MyService myService() {
        return new MyServiceImpl();
    }
}
  • @Configuration 标记配置类。
  • @Bean 定义 Bean,等价于 XML 中的 <bean>

实例化:

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

依赖解决过程

容器解析 Bean 依赖的步骤:

  1. 使用配置元数据创建和初始化 ApplicationContext
  2. 为每个 Bean 提供依赖(属性或构造函数参数)。
  3. 将值或引用转换为实际类型。

Spring 在容器加载时验证配置,延迟设置属性以避免循环依赖问题。单例 Bean 默认预实例化,可通过配置改为延迟初始化。