IoC 容器
简介
Spring 的控制反转 (IoC) 容器。IoC 也称为依赖注入 (DI)。这是一个过程。对象仅通过构造函数参数、工厂方法的参数设置的属性来定义它们的依赖关系, 然后容器在创建 bean 时注入这些依赖项。
在IoC模式下,控制权发生了反转,即从开发人员自己创建转移到了IoC容器,所有组件不再由应用程序自己创建和配置,而是由IoC容器负责,所以叫控制反转。
BeanFactory
接口提供了一种高级配置机制,能够管理任何类型的对象。 ApplicationContext
是 的子接口BeanFactory
。它补充说:
- 更容易与 Spring 的 AOP 功能集成
- 消息资源处理(用于国际化)
- 活动发布
- 应用层特定上下文,例如
WebApplicationContext
用于 Web 应用程序的上下文。
简而言之,它BeanFactory
提供了配置框架和基本功能,并ApplicationContext
增加了更多的企业特定功能。
在 Spring 中,由 Spring IoC 容器管理的对象称为 bean。bean 是由 Spring IoC 容器实例化、组装和管理的对象。否则,bean 只是应用程序中的众多对象之一。Bean 以及它们之间的依赖关系反映在容器使用的配置元数据中。
容器概述
ApplicationContext`接口代表 Spring IoC 容器,负责实例化、配置和组装 bean。容器通过读取配置元数据来获取关于要实例化、配置和组装哪些对象的指令。配置元数据以 XML、Java 注释或 Java 代码表示。它允许您表达组成应用程序的对象以及这些对象之间丰富的相互依赖关系。
ApplicationContext
Spring 提供了该接口的几个实现。在独立应用程序中,通常会创建ClassPathXmlApplicationContext
或的实例 FileSystemXmlApplicationContext
。虽然 XML 一直是定义配置元数据的传统格式,但您可以通过提供少量 XML 配置来以声明方式启用对这些附加元数据格式的支持,从而指示容器使用 Java 注释或代码作为元数据格式。
配置元数据
Spring IoC 容器使用一种形式的配置元数据。此配置元数据表示您作为应用程序开发人员如何告诉 Spring 容器实例化、配置和组装应用程序中的对象。
配置元数据传统上以简单直观的 XML 格式提供,本章大部分内容都使用这种格式来传达 Spring IoC 容器的关键概念和特性。
有关在 Spring 容器中使用其他形式的元数据的信息,请参阅:
- 基于注解的配置:Spring 2.5 引入了对基于注解的配置元数据的支持。
- 基于 Java 的配置
Spring 配置包含容器必须管理的至少一个,通常是多个 bean 定义。基于 XML 的配置元数据将这些 bean 配置为<bean/>
顶级元素内的<beans/>
元素。Java 配置通常@Bean
在类中使用 -annotated 方法@Configuration
。
实例化一个容器
提供给构造函数的一个或多个位置路径ApplicationContext
是资源字符串,允许容器从各种外部资源(例如本地文件系统、Java 等)加载配置元数据。
ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");
编写基于 XML 的配置元数据
让 bean 定义多个 XML 文件会很有用。通常,每个单独的 XML 配置文件都代表架构中的一个逻辑层或模块。
<beans>
<import resource="services.xml"/>
<import resource="resources/messageSource.xml"/>
<bean id="bean1" class="..."/>
</beans>
使用容器
ApplicationContext
是一个高级工厂的接口,能够维护不同 bean 及其依赖项的注册表。
// create and configure beans
ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");
// retrieve configured instance
PetStoreService service = context.getBean("petStore", PetStoreService.class);
// use configured instance
List<String> userList = service.getUsernameList();
Bean概述
Spring IoC 容器管理一个或多个 bean。这些 bean 是使用您提供给容器的配置元数据创建的。
在容器本身中,这些 bean 定义表示为BeanDefinition
对象,其中包含(以及其他信息)以下元数据:
- 一个包限定的类名:通常是被定义的 bean 的实际实现类。
- Bean 行为配置元素,它说明 bean 在容器中的行为方式(范围、生命周期回调等)。
- 对 bean 完成工作所需的其他 bean 的引用。这些引用也称为协作者或依赖项。
- 要在新创建的对象中设置的其他配置设置——例如,池的大小限制或在管理连接池的 bean 中使用的连接数。
注意:
Bean 元数据和手动提供的单例实例需要尽早注册,官方不支持在运行时注册新 bean,并可能导致并发访问异常、bean 容器中的状态不一致。
命名 Bean
每个 bean 都有一个或多个标识符。这些标识符在承载 bean 的容器中必须是唯一的。一个 bean 通常只有一个标识符。但是,如果它需要多个,则可以将多余的视为别名。
在基于 XML 的配置元数据中,您可以使用id
属性、name
属性或两者来指定 bean 标识符。
您不需要为 bean 提供 name或 id
。如果您不显式提供 name
或id
,则容器会为该 bean 生成一个唯一名称。但是,如果您想通过名称引用该 bean,通过使用ref
元素或服务定位器样式查找,您必须提供名称。
实例化 Bean
bean 定义本质上是创建一个或多个对象的方法。
如果您使用基于 XML 的配置元数据,您可以在元素的class
属性中指定要实例化的对象的类型。
您可以通过以下两种方式之一使用该属性:
- 通常,在容器本身通过反射调用其构造函数直接创建 bean 的情况下,指定要构造的 bean 类,有点等价于 Java 代码中的
new
运算符。 static
指定包含被调用以创建对象 的工厂方法的实际类,在不太常见的情况下,容器调用static
类上的工厂方法来创建 bean。调用static
工厂方法返回的对象类型可能是同一个类,也可能完全是另一个类。
使用构造函数进行实例化
当您通过构造方法创建 bean 时,所有普通类都可以被 Spring 使用并兼容。也就是说,正在开发的类不需要实现任何特定的接口或以特定的方式进行编码。只需指定 bean 类就足够了。但是,根据您用于该特定 bean 的 IoC 类型,您可能需要一个默认(空)构造函数。
<bean id="exampleBean" class="examples.ExampleBean"/>
使用静态工厂方法进行实例化
在定义使用静态工厂方法创建的 bean 时,使用class
属性指定包含static
工厂方法的类,使用命名属性factory-method
指定工厂方法本身的名称。您应该能够调用此方法(使用可选参数,如后所述)并返回一个活动对象,该对象随后被视为是通过构造函数创建的。这种 bean 定义的一种用途是static
在遗留代码中调用工厂。
<bean id="clientService"
class="examples.ClientService"
factory-method="createInstance"/>
使用实例工厂方法进行实例化
与通过静态工厂方法进行实例化类似,使用实例工厂方法进行实例化会从容器中调用现有 bean 的非静态方法来创建新 bean。要使用此机制,请将class
属性留空,并在factory-bean
属性中指定当前(或父级或祖先)容器中包含要调用以创建对象的实例方法的 bean 的名称。factory-method
使用属性设置工厂方法本身的名称。以下示例显示了如何配置这样的 bean:
<!-- the factory bean, which contains a method called createInstance() -->
<bean id="serviceLocator" class="examples.DefaultServiceLocator">
<!-- inject any dependencies required by this locator bean -->
</bean>
<!-- the bean to be created via the factory bean -->
<bean id="clientService"
factory-bean="serviceLocator"
factory-method="createClientServiceInstance"/>
public class DefaultServiceLocator {
private static ClientService clientService = new ClientServiceImpl();
public ClientService createClientServiceInstance() {
return clientService;
}
}