对于最新稳定版本,请使用 Spring Framework 7.0.6spring-doc.cadn.net.cn

容器概述

org.springframework.context.ApplicationContext 接口代表 Spring IoC 容器,负责实例化、配置和组装 bean。该容器通过读取配置元数据来获取有关要实例化、配置和组装哪些对象的指令。配置元数据可以采用 XML、Java 注解或 Java 代码的形式。它允许你表达构成应用程序的对象以及这些对象之间复杂的相互依赖关系。spring-doc.cadn.net.cn

Spring 提供了 ApplicationContext 接口的多种实现。在独立应用程序中,通常会创建 ClassPathXmlApplicationContextFileSystemXmlApplicationContext 的实例。 虽然 XML 一直是定义配置元数据的传统格式,但您可以通过提供少量 XML 配置来声明式地启用对这些额外元数据格式的支持,从而指示容器使用 Java 注解或代码作为元数据格式。spring-doc.cadn.net.cn

在大多数应用场景中,通常不需要显式编写用户代码来实例化一个或多个 Spring IoC 容器。例如,在 Web 应用场景中,应用程序的 web.xml 文件中通常只需大约八行(左右)样板式的 Web 描述符 XML 配置就足够了(参见 Web 应用程序的便捷 ApplicationContext 实例化方式)。 如果你使用 Spring Tools for Eclipse(一个基于 Eclipse 的开发环境),只需几次鼠标点击或键盘操作,即可轻松创建此类样板配置。spring-doc.cadn.net.cn

下图展示了 Spring 工作原理的高层视图。您的应用程序类与配置元数据相结合,这样在创建并初始化 ApplicationContext 之后,您就拥有了一个完全配置好且可运行的系统或应用程序。spring-doc.cadn.net.cn

container magic
图1. Spring IoC容器

配置元数据

如上图所示,Spring IoC 容器使用一种配置元数据。这种配置元数据代表了作为应用程序开发人员,您如何告诉 Spring 容器去实例化、配置和组装应用程序中的对象。spring-doc.cadn.net.cn

配置元数据传统上以一种简单直观的 XML 格式提供, 本章大部分内容都使用这种格式来阐述 Spring IoC 容器的核心概念和特性。spring-doc.cadn.net.cn

基于 XML 的元数据并不是唯一允许的配置元数据形式。 Spring IoC 容器本身与实际编写这种配置元数据所采用的格式完全解耦。如今,许多开发者为其 Spring 应用选择基于 Java 的配置

有关在 Spring 容器中使用其他形式元数据的信息,请参见:spring-doc.cadn.net.cn

Spring 配置至少包含一个,通常包含多个由容器管理的 bean 定义。基于 XML 的配置元数据将这些 bean 配置为顶级 <bean/> 元素内部的 <beans/> 元素。Java 配置通常在带有 @Bean 注解的类中使用带有 @Configuration 注解的方法。spring-doc.cadn.net.cn

这些 Bean 定义对应于构成您应用程序的实际对象。 通常,您会定义服务层对象、持久层对象(例如仓库或数据访问对象(DAO))、 表示层对象(例如 Web 控制器),以及基础设施对象(例如 JPA 的 EntityManagerFactory、JMS 队列等)。 通常,不会在容器中配置细粒度的领域对象,因为创建和加载领域对象 通常是仓库和业务逻辑的职责。spring-doc.cadn.net.cn

以下示例展示了基于 XML 的配置元数据的基本结构:spring-doc.cadn.net.cn

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
		https://www.springframework.org/schema/beans/spring-beans.xsd">

	<bean id="..." class="..."> (1) (2)
		<!-- collaborators and configuration for this bean go here -->
	</bean>

	<bean id="..." class="...">
		<!-- collaborators and configuration for this bean go here -->
	</bean>

	<!-- more bean definitions go here -->

</beans>
1 id 属性是一个用于标识单个 bean 定义的字符串。
2 class 属性定义了 bean 的类型,并使用完全限定的类名。

id 属性的值可用于引用协作对象。本示例中未显示用于引用协作对象的 XML。更多信息请参见 依赖关系spring-doc.cadn.net.cn

实例化容器

提供给 ApplicationContext 构造函数的位置路径(一个或多个)是资源字符串,允许容器从各种外部资源(例如本地文件系统、Java CLASSPATH 等)加载配置元数据。spring-doc.cadn.net.cn

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

在了解了 Spring 的 IoC 容器之后,您可能希望进一步了解 Spring 的Resource抽象(如资源(Resources)中所述),它提供了一种便捷的机制,用于从 URI 语法定义的位置读取 InputStream。特别是,Resource路径被用于构建应用上下文,如应用上下文和资源路径中所述。spring-doc.cadn.net.cn

以下示例展示了服务层对象的 (services.xml) 配置文件:spring-doc.cadn.net.cn

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
		https://www.springframework.org/schema/beans/spring-beans.xsd">

	<!-- services -->

	<bean id="petStore" class="org.springframework.samples.jpetstore.services.PetStoreServiceImpl">
		<property name="accountDao" ref="accountDao"/>
		<property name="itemDao" ref="itemDao"/>
		<!-- additional collaborators and configuration for this bean go here -->
	</bean>

	<!-- more bean definitions for services go here -->

</beans>

以下示例展示了数据访问对象的 daos.xml 文件:spring-doc.cadn.net.cn

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
		https://www.springframework.org/schema/beans/spring-beans.xsd">

	<bean id="accountDao"
		class="org.springframework.samples.jpetstore.dao.jpa.JpaAccountDao">
		<!-- additional collaborators and configuration for this bean go here -->
	</bean>

	<bean id="itemDao" class="org.springframework.samples.jpetstore.dao.jpa.JpaItemDao">
		<!-- additional collaborators and configuration for this bean go here -->
	</bean>

	<!-- more bean definitions for data access objects go here -->

</beans>

在前面的示例中,服务层由 PetStoreServiceImpl 类以及两个数据类型分别为 JpaAccountDaoJpaItemDao 的数据访问对象组成(基于 JPA 对象关系映射标准)。property name 元素引用的是 JavaBean 属性的名称,而 ref 元素引用的是另一个 Bean 定义的名称。idref 元素之间的这种关联表达了协作对象之间的依赖关系。有关配置对象依赖关系的详细信息,请参阅 依赖关系spring-doc.cadn.net.cn

组合基于 XML 的配置元数据

将 Bean 定义分散在多个 XML 文件中可能是很有用的。通常,每个单独的 XML 配置文件代表架构中的一个逻辑层或模块。spring-doc.cadn.net.cn

你可以使用应用上下文的构造函数从所有这些 XML 片段中加载 bean 定义。该构造函数接受多个 Resource 位置,如上一节所示。或者,也可以使用一个或多个 <import/> 元素从其他一个或多个文件中加载 bean 定义。以下示例展示了如何实现这一点:spring-doc.cadn.net.cn

<beans>
	<import resource="services.xml"/>
	<import resource="resources/messageSource.xml"/>
	<import resource="/resources/themeSource.xml"/>

	<bean id="bean1" class="..."/>
	<bean id="bean2" class="..."/>
</beans>

在前面的示例中,外部 bean 定义从三个文件加载:services.xmlmessageSource.xmlthemeSource.xml。所有位置路径都是相对于执行导入的定义文件而言的,因此 services.xml 必须与执行导入的文件位于同一目录或类路径位置,而 messageSource.xmlthemeSource.xml 必须位于导入文件所在位置下方的 resources 目录中。如您所见,开头的斜杠会被忽略。然而,鉴于这些路径是相对路径,最好完全不要使用斜杠。被导入文件的内容(包括顶层的 <beans/> 元素)必须是符合 Spring Schema 的有效 XML bean 定义。spring-doc.cadn.net.cn

可以(但不推荐)使用相对路径“../”引用父目录中的文件。这样做会创建对当前应用程序外部文件的依赖。尤其不建议在classpath: URL中使用此类引用(例如classpath:../services.xml),因为运行时解析过程会选择“最近”的类路径根目录,然后查找其父目录。类路径配置的更改可能导致选择一个不同的、错误的目录。spring-doc.cadn.net.cn

你始终可以使用完全限定的资源位置,而不是相对路径:例如,file:C:/config/services.xmlclasspath:/config/services.xml。但请注意,这样做会将你的应用程序配置与特定的绝对位置耦合在一起。通常更推荐为这类绝对位置保留一层间接引用——例如,通过在运行时根据 JVM 系统属性解析的 “${…​}” 占位符。spring-doc.cadn.net.cn

该命名空间本身提供了导入指令功能。除了基本的 bean 定义之外,Spring 还在一系列 XML 命名空间中提供了更多配置特性——例如 contextutil 命名空间。spring-doc.cadn.net.cn

Groovy Bean 定义 DSL

作为外部化配置元数据的另一个示例,Bean 定义也可以使用 Spring 的 Groovy Bean 定义 DSL(领域特定语言)来表达,这种 DSL 在 Grails 框架中广为人知。 通常,此类配置位于一个“.groovy”文件中,其结构如下例所示:spring-doc.cadn.net.cn

beans {
	dataSource(BasicDataSource) {
		driverClassName = "org.hsqldb.jdbcDriver"
		url = "jdbc:hsqldb:mem:grailsDB"
		username = "sa"
		password = ""
		settings = [mynew:"setting"]
	}
	sessionFactory(SessionFactory) {
		dataSource = dataSource
	}
	myService(MyService) {
		nestedBean = { AnotherBean bean ->
			dataSource = dataSource
		}
	}
}

这种配置方式在很大程度上等同于 XML bean 定义,甚至支持 Spring 的 XML 配置命名空间。它还允许通过 importBeans 指令导入 XML bean 定义文件。spring-doc.cadn.net.cn

使用容器

ApplicationContext 是一个高级工厂的接口,能够维护不同 bean 及其依赖关系的注册表。通过使用方法 T getBean(String name, Class<T> requiredType),你可以获取 bean 的实例。spring-doc.cadn.net.cn

ApplicationContext 允许你读取 bean 定义并访问它们,如下例所示:spring-doc.cadn.net.cn

// 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();
   import org.springframework.beans.factory.getBean

// create and configure beans
   val context = ClassPathXmlApplicationContext("services.xml", "daos.xml")

   // retrieve configured instance
   val service = context.getBean<PetStoreService>("petStore")

   // use configured instance
   var userList = service.getUsernameList()

使用 Groovy 配置时,引导过程看起来非常相似。它使用了一个不同的上下文实现类,该类支持 Groovy(但也能够理解 XML bean 定义)。 以下示例展示了 Groovy 配置:spring-doc.cadn.net.cn

ApplicationContext context = new GenericGroovyApplicationContext("services.groovy", "daos.groovy");
val context = GenericGroovyApplicationContext("services.groovy", "daos.groovy")

最灵活的变体是 GenericApplicationContext 与读取器委托(reader delegates)结合使用——例如,与用于 XML 文件的 XmlBeanDefinitionReader 结合使用,如下例所示:spring-doc.cadn.net.cn

GenericApplicationContext context = new GenericApplicationContext();
new XmlBeanDefinitionReader(context).loadBeanDefinitions("services.xml", "daos.xml");
context.refresh();
val context = GenericApplicationContext()
XmlBeanDefinitionReader(context).loadBeanDefinitions("services.xml", "daos.xml")
context.refresh()

你也可以像下面示例所示,对 Groovy 文件使用 GroovyBeanDefinitionReaderspring-doc.cadn.net.cn

GenericApplicationContext context = new GenericApplicationContext();
new GroovyBeanDefinitionReader(context).loadBeanDefinitions("services.groovy", "daos.groovy");
context.refresh();
val context = GenericApplicationContext()
GroovyBeanDefinitionReader(context).loadBeanDefinitions("services.groovy", "daos.groovy")
context.refresh()

你可以在同一个ApplicationContext中混合使用这些读取器委托,从多种配置源读取 bean 定义。spring-doc.cadn.net.cn

然后,您可以使用 getBean 方法来获取 Bean 的实例。ApplicationContext 接口还提供了其他一些用于获取 Bean 的方法,但理想情况下,您的应用程序代码绝不应使用这些方法。实际上,您的应用程序代码完全不应调用 getBean() 方法,从而完全不依赖于 Spring 的 API。例如,Spring 与 Web 框架的集成支持对各种 Web 框架组件(如控制器和 JSF 管理的 Bean)进行依赖注入,允许您通过元数据(例如自动装配注解)声明对特定 Bean 的依赖。spring-doc.cadn.net.cn