容器概述
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 配置通常在 @Configuration 类中使用带有 @Bean 注解的方法,每个方法对应一个 Bean 定义。
这些bean定义对应于构成您应用程序的实际对象。
通常,您会定义服务层对象、持久层对象(如
仓库或数据访问对象(DAO),表示层对象(如Web控制器),
基础设施对象(如JPA EntityManagerFactory、JMS队列等)。
通常,不会在容器中配置细粒度的域对象,因为创建和加载域对象通常是仓库和业务逻辑的责任。
将 XML 作为外部配置 DSL
基于XML的配置元数据在顶级 <beans/> 元素内将这些bean配置为 <bean/> 元素。以下示例展示了基于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定义。
|
使用相对 "../" 路径引用父目录中的文件是可能的,但不推荐。这样做会创建对当前应用程序外部文件的依赖。特别是,对于 您可以始终使用完全限定的资源位置而不是相对路径:例如, |
命名空间本身提供了导入指令功能。Spring 提供的其他 XML 命名空间中还包含超出普通 bean 定义的进一步配置功能——例如,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")
最灵活的变体是与reader委托结合使用的GenericApplicationContext,例如,对于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 的依赖。