跳到主要内容
版本:7.0.3

容器概述

Hunyuan 7b 中英对照 Container Overview

org.springframework.context.ApplicationContext接口代表了Spring的IoC容器,负责实例化、配置和组装Bean。容器通过读取配置元数据来获取关于需要实例化、配置和组装的组件的指令。配置元数据可以表现为带有注解的组件类、具有工厂方法的配置类,或者外部的XML文件或Groovy脚本。无论是哪种格式,你都可以利用它们来构建你的应用程序以及这些组件之间的复杂依赖关系。

ApplicationContext接口的几种实现是Spring核心的一部分。在独立应用程序中,通常会创建AnnotationConfigApplicationContextClassPathXmlApplicationContext的实例。

在大多数应用场景中,不需要显式的用户代码来实例化一个或多个Spring IoC容器。例如,在一个普通的Web应用场景中,只需在应用的web.xml文件中编写一个简单的模板Web描述符XML即可(参见Web应用的便捷ApplicationContext实例化)。而在Spring Boot场景中,基于常见的设置规范,应用程序上下文会自动被初始化。

下图展示了Spring的工作原理概述。您的应用程序类与配置元数据相结合,这样在创建并初始化了ApplicationContext之后,您就拥有了一个完全配置好且可执行的系统或应用程序。

容器魔法

图1. Spring IoC容器

配置元数据

如前面的图表所示,Spring IoC容器消耗一种配置元数据。这种配置元数据代表了作为应用程序开发者的你,如何告诉Spring容器来实例化、配置以及组装应用程序中的组件。

Spring的IoC容器本身与这些配置元数据实际编写的格式是完全解耦的。如今,许多开发者为他们的Spring应用程序选择基于Java的配置

Spring配置至少包含一个,通常还包含多个需要容器管理的bean定义。Java配置通常在@Configuration类中使用标注有@Bean的方法,每个方法对应一个bean定义。

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

XML作为外部配置DSL

基于XML的配置元数据将这些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>
  • id 属性是一个字符串,用于标识各个 Bean 的定义。

  • class 属性定义了 Bean 的类型,并使用完全限定的类名。

id 属性的值可以用来引用协作对象。此示例中未展示用于引用协作对象的 XML 代码。如需更多信息,请参阅 Dependencies

为了实例化一个容器,需要向ClassPathXmlApplicationContext的构造函数提供XML资源文件的位置路径或多个路径,这样容器就可以从各种外部资源(如本地文件系统、Java的CLASSPATH等)加载配置元数据。

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

在了解了Spring的IoC容器之后,你可能还想进一步了解Spring的Resource抽象(如Resources中所描述)——它提供了一种方便的机制,可以从URI语法定义的位置读取InputStream。特别是,Resource路径被用来构建应用程序上下文(application contexts),这一点在Application Contexts and Resource Paths中有详细说明。

以下示例展示了服务层对象(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类以及两个数据访问对象JpaAccountDaoJpaItemDao(基于JPA对象关系映射标准)组成。property name元素指的是JavaBean属性的名称,而ref元素则指的是另一个bean定义的名称。idref元素之间的这种关联表达了协作对象之间的依赖关系。关于配置对象依赖关系的详细信息,请参见Dependencies

组成基于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.xmlmessageSource.xml文件中加载的。所有的路径都是相对于进行导入的定义文件的,因此services.xml必须与进行导入的文件位于同一个目录或类路径中,而messageSource.xml则必须位于导入文件所在目录下的resources子目录中。可以看到,路径开头的斜杠会被忽略。然而,由于这些路径是相对路径,最好根本不使用斜杠。被导入文件的内容,包括顶层的<beans/>元素,都必须是根据Spring Schema规范编写的有效XML bean定义。

备注

虽然可以使用相对路径 „../“ 来引用上级目录中的文件,但并不推荐这样做。因为这样会使得应用程序依赖于当前目录之外的文件。特别是对于 classpath: URL(例如 classpath:../services.xml),运行时解析过程会选择“最近的”类路径根目录,然后在该目录的父目录中查找文件。类路径配置的更改可能会导致选择到错误的目录。

您始终可以使用完整的资源路径来代替相对路径,例如 file:C:/config/services.xmlclasspath:/config/services.xml。但需要注意的是,这样会使应用程序的配置依赖于特定的绝对路径。通常来说,最好对这些绝对路径保持一定的间接性,例如通过 „${…​}" 占位符,在运行时根据 JVM 系统属性来解析这些占位符。

命名空间本身就提供了导入指令的功能。除了简单的bean定义之外,Spring还提供了一些其他的配置功能,这些功能通过特定的XML命名空间来实现——例如contextutil命名空间。

使用容器

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

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();

使用Groovy进行配置时,启动过程看起来非常相似。它有一个不同的上下文实现类,该类能够识别Groovy(同时也能够理解XML豆定义)。以下示例展示了如何使用Groovy进行配置:

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

最灵活的变体是将GenericApplicationContext与读取器代理(reader delegates)结合使用——例如,对于XML文件可以使用XmlBeanDefinitionReader,如下例所示:

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

您也可以对Groovy文件使用GroovyBeanDefinitionReader,如下例所示:

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

你可以在同一个ApplicationContext上混合使用这些读取委托(reader delegates),从多种配置来源中读取bean定义。

然后你可以使用getBean来获取你的bean实例。ApplicationContext接口还有其他一些用于获取bean的方法,但理想情况下,你的应用程序代码根本不应该使用这些方法。实际上,你的应用程序代码中根本不应该有对getBean()方法的调用,因此也不应该依赖于Spring的API。例如,Spring与Web框架的集成为各种Web框架组件(如控制器和JSF管理的bean)提供了依赖注入功能,让你可以通过元数据(如自动装配注解)来声明对特定bean的依赖。