|
此版本仍在开发中,尚未被视为稳定版。如需最新稳定版本,请使用 Spring Framework 7.0.6! |
容器概述
org.springframework.context.ApplicationContext 接口代表 Spring IoC 容器,负责实例化、配置和装配 Bean。
容器通过读取配置元数据来获取有关要实例化、配置和装配哪些组件的指令。配置元数据可以表示为带注解的组件类、包含工厂方法的配置类,或者外部的 XML 文件或 Groovy 脚本。无论采用哪种格式,您都可以组合您的应用程序以及这些组件之间丰富的相互依赖关系。
ApplicationContext 接口的多个实现是 Spring 核心的一部分。
在独立应用程序中,通常会创建
AnnotationConfigApplicationContext
或 ClassPathXmlApplicationContext 的实例。
在大多数应用场景中,不需要显式编写用户代码来实例化一个或多个 Spring IoC 容器。例如,在普通的 Web 应用场景中,只需在应用程序的 web.xml 文件中提供一个简单的样板 Web 描述符 XML 即可(参见
Web 应用程序的便捷 ApplicationContext 实例化方式)。
在 Spring Boot 场景中,应用程序上下文会根据通用的配置约定自动为你引导启动。
下图展示了 Spring 工作原理的高层视图。您的应用程序类与配置元数据相结合,这样在创建并初始化 ApplicationContext 之后,您就拥有了一个完全配置好且可运行的系统或应用程序。
配置元数据
如上图所示,Spring IoC 容器使用一种配置元数据。这种配置元数据代表了作为应用程序开发人员的你,如何告诉 Spring 容器去实例化、配置和组装应用程序中的组件。
Spring IoC 容器本身与配置元数据的实际编写格式完全解耦。如今,许多开发者为其 Spring 应用选择基于 Java 的配置:
-
基于注解的配置:在应用程序的组件类上使用基于注解的配置元数据来定义 bean。
-
基于 Java 的配置:通过使用基于 Java 的配置类,在应用程序类外部定义 Bean。要使用这些功能,请参阅
@Configuration、@Bean、@Import和@DependsOn注解。
Spring 配置包含至少一个、通常为多个由容器管理的 bean 定义。Java 配置通常在 @Bean 类中使用带有 @Configuration 注解的方法,每个方法对应一个 bean 定义。
这些 Bean 定义对应于构成您应用程序的实际对象。
通常,您会定义服务层对象、持久层对象(例如仓库或数据访问对象(DAO))、
表示层对象(例如 Web 控制器),以及基础设施对象(例如 JPA 的 EntityManagerFactory、JMS 队列等)。
通常,不会在容器中配置细粒度的领域对象,因为创建和加载领域对象
通常是仓库和业务逻辑的职责。
XML 作为外部配置领域特定语言
基于 XML 的配置元数据将这些 bean 配置为顶级 <bean/> 元素内的 <beans/> 元素。以下示例展示了基于 XML 的配置元数据的基本结构:
<?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。更多信息请参见 依赖关系。
要实例化一个容器,需要向 ClassPathXmlApplicationContext 构造函数提供一个或多个 XML 资源文件的位置路径,以便容器能够从各种外部资源(例如本地文件系统、Java CLASSPATH 等)加载配置元数据。
-
Java
-
Kotlin
ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");
val context = ClassPathXmlApplicationContext("services.xml", "daos.xml")
|
在了解了 Spring 的 IoC 容器之后,您可能希望进一步了解 Spring 的 |
以下示例展示了服务层对象的 (services.xml) 配置文件:
<?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 文件:
<?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 类以及两个数据类型分别为 JpaAccountDao 和 JpaItemDao 的数据访问对象组成(基于 JPA 对象关系映射标准)。property name 元素引用的是 JavaBean 属性的名称,而 ref 元素引用的是另一个 Bean 定义的名称。id 与 ref 元素之间的这种关联表达了协作对象之间的依赖关系。有关配置对象依赖关系的详细信息,请参阅 依赖关系。
组合基于 XML 的配置元数据
将 Bean 定义分散在多个 XML 文件中可能是很有用的。通常,每个单独的 XML 配置文件代表架构中的一个逻辑层或模块。
你可以使用 ClassPathXmlApplicationContext 构造函数从 XML 片段加载 bean 定义。该构造函数接受多个 Resource 位置,如上一节所示。或者,也可以使用一个或多个 <import/> 元素从其他一个或多个文件中加载 bean 定义。以下示例展示了如何实现这一点:
<beans>
<import resource="services.xml"/>
<import resource="resources/messageSource.xml"/>
<bean id="bean1" class="..."/>
<bean id="bean2" class="..."/>
</beans>
在前面的示例中,外部的 bean 定义从 services.xml 和 messageSource.xml 文件中加载。所有位置路径都是相对于执行导入的定义文件而言的,因此 services.xml 必须与执行导入的文件位于同一目录或类路径位置,而 messageSource.xml 则必须位于导入文件所在位置下方的 resources 目录中。如您所见,开头的斜杠会被忽略。然而,鉴于这些路径是相对路径,最好完全不要使用斜杠。被导入文件的内容(包括顶层的 <beans/> 元素)必须是符合 Spring Schema 的有效 XML bean 定义。
|
可以(但不推荐)使用相对路径“../”引用父目录中的文件。这样做会创建对当前应用程序外部文件的依赖。尤其不建议在 你始终可以使用完全限定的资源位置,而不是相对路径:例如, |
该命名空间本身提供了导入指令功能。除了基本的 bean 定义之外,Spring 还在一系列 XML 命名空间中提供了更多配置特性——例如 context 和 util 命名空间。
使用容器
ApplicationContext 是一个高级工厂的接口,能够维护不同 bean 及其依赖关系的注册表。通过使用方法
T getBean(String name, Class<T> requiredType),你可以获取 bean 的实例。
ApplicationContext 允许你读取 bean 定义并访问它们,如下例所示:
-
Java
-
Kotlin
// 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 配置:
-
Java
-
Kotlin
ApplicationContext context = new GenericGroovyApplicationContext("services.groovy", "daos.groovy");
val context = GenericGroovyApplicationContext("services.groovy", "daos.groovy")
最灵活的变体是 GenericApplicationContext 与读取器委托(reader delegates)结合使用——例如,与用于 XML 文件的 XmlBeanDefinitionReader 结合使用,如下例所示:
-
Java
-
Kotlin
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 文件使用 GroovyBeanDefinitionReader:
-
Java
-
Kotlin
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 定义。
然后,您可以使用 getBean 方法来获取 Bean 的实例。ApplicationContext 接口还提供了其他一些用于获取 Bean 的方法,但理想情况下,您的应用程序代码绝不应使用这些方法。实际上,您的应用程序代码完全不应调用 getBean() 方法,从而完全不依赖于 Spring 的 API。例如,Spring 与 Web 框架的集成支持对各种 Web 框架组件(如控制器和 JSF 管理的 Bean)进行依赖注入,允许您通过元数据(例如自动装配注解)声明对特定 Bean 的依赖。