Container Overview

org.springframework.context.ApplicationContext 接口表示 Spring IoC 容器,负责实例化、配置和装配 bean。容器通过读取配置元数据来获取有关要实例化、配置和装配的组件的说明。配置元数据可以表示为带注释的组件类、带工厂方法的配置类或外部 XML 文件或 Groovy 脚本。使用任一格式,您都可以编制您的应用程序以及那些组件之间丰富的相互依赖关系。

The org.springframework.context.ApplicationContext interface represents the Spring IoC container and is responsible for instantiating, configuring, and assembling the beans. The container gets its instructions on the components to instantiate, configure, and assemble by reading configuration metadata. The configuration metadata can be represented as annotated component classes, configuration classes with factory methods, or external XML files or Groovy scripts. With either format, you may compose your application and the rich interdependencies between those components.

ApplicationContext 接口的几个实现是 core Spring 的一部分。在独立应用程序中,通常创建https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/annotation/AnnotationConfigApplicationContext.html[AnnotationConfigApplicationContext]或https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/support/ClassPathXmlApplicationContext.html[ClassPathXmlApplicationContext]的实例。

Several implementations of the ApplicationContext interface are part of core Spring. In stand-alone applications, it is common to create an instance of AnnotationConfigApplicationContext or ClassPathXmlApplicationContext.

在大多数应用程序场景中,不需要显式用户代码来实例化 Spring IoC 容器的一个或多个实例。例如,在普通的 Web 应用程序场景中,应用程序的 web.xml 文件中的简单样板 Web 描述符 XML 就足够了(见 Convenient ApplicationContext Instantiation for Web Applications)。在 Spring Boot 场景中,应用程序上下文将根据常见的设置约定隐式为你引导。

In most application scenarios, explicit user code is not required to instantiate one or more instances of a Spring IoC container. For example, in a plain web application scenario, a simple boilerplate web descriptor XML in the web.xml file of the application suffices (see Convenient ApplicationContext Instantiation for Web Applications). In a Spring Boot scenario, the application context is implicitly bootstrapped for you based on common setup conventions.

下图显示了 Spring 的工作方式的高级视图。您的应用程序类与配置元数据相结合,以便在创建并初始化 ApplicationContext 之后,您就会拥有一个完全配置且可执行的系统或应用程序。

The following diagram shows a high-level view of how Spring works. Your application classes are combined with configuration metadata so that, after the ApplicationContext is created and initialized, you have a fully configured and executable system or application. .The Spring IoC container image::container-magic.png[]

Configuration Metadata

如上图所示,Spring IoC 容器使用配置元数据的某个格式。作为应用程序开发人员,您可以使用此配置元数据告知 Spring 容器如何在您的应用程序中实例化、配置和装配组件。

As the preceding diagram shows, the Spring IoC container consumes a form of configuration metadata. This configuration metadata represents how you, as an application developer, tell the Spring container to instantiate, configure, and assemble the components in your application.

Spring IoC 容器本身与该配置元数据实际编写的格式完全分离。如今,许多开发人员为他们的 Spring 应用程序选择Java-based configuration

The Spring IoC container itself is totally decoupled from the format in which this configuration metadata is actually written. These days, many developers choose Java-based configuration for their Spring applications:

Spring 配置至少包含一个(通常多个)容器必须管理的 bean 定义。Java 配置通常在 @Configuration 类中使用带 @Bean 注释的方法,每个方法对应一个 bean 定义。

Spring configuration consists of at least one and typically more than one bean definition that the container must manage. Java configuration typically uses @Bean-annotated methods within a @Configuration class, each corresponding to one bean definition.

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

These bean definitions correspond to the actual objects that make up your application. Typically, you define service layer objects, persistence layer objects such as repositories or data access objects (DAOs), presentation objects such as Web controllers, infrastructure objects such as a JPA EntityManagerFactory, JMS queues, and so forth. Typically, one does not configure fine-grained domain objects in the container, because it is usually the responsibility of repositories and business logic to create and load domain objects.

XML as an External Configuration DSL

基于 XML 的配置元数据将这些 bean 配置为顶级 <beans/> 元素内的 <bean/> 元素。以下示例显示基于 XML 的配置元数据的基本结构:

XML-based configuration metadata configures these beans as <bean/> elements inside a top-level <beans/> element. The following example shows the basic structure of XML-based configuration metadata:

<?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 The id attribute is a string that identifies the individual bean definition.
2 The class attribute defines the type of the bean and uses the fully qualified class name.

`id`属性的值可用于引用协作对象。此示例中未显示引用协作对象的 XML。有关更多信息,请参阅Dependencies

The value of the id attribute can be used to refer to collaborating objects. The XML for referring to collaborating objects is not shown in this example. See Dependencies for more information.

要实例化容器,需要将 XML 资源文件的位置路径或路径提供给 ClassPathXmlApplicationContext 构造器,该构造器允许容器从各种外部资源(例如本地文件系统、Java CLASSPATH 等)加载配置元数据。

For instantiating a container, the location path or paths to the XML resource files need to be supplied to a ClassPathXmlApplicationContext constructor that let the container load configuration metadata from a variety of external resources, such as the local file system, the Java CLASSPATH, and so on.

  • Java

  • Kotlin

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

在你了解了 Spring 的 IoC 容器之后,你可能希望更多地了解 Spring 的 Resource 抽象(如 Resources 所述),它提供了一种方便的机制来从在 URI 语法中定义的位置读取 InputStream。特别是,Resource 路径用于构造应用程序上下文,如 Application Contexts and Resource Paths 所述。

After you learn about Spring’s IoC container, you may want to know more about Spring’s Resource abstraction (as described in Resources) which provides a convenient mechanism for reading an InputStream from locations defined in a URI syntax. In particular, Resource paths are used to construct applications contexts, as described in Application Contexts and Resource Paths.

以下示例显示服务层对象 (services.xml) 配置文件:

The following example shows the service layer objects (services.xml) configuration file:

<?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 文件:

The following example shows the data access objects daos.xml file:

<?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 类和两个数据访问对象(基于 JPA 对象关系映射标准)的类型为 JpaAccountDaoJpaItemDao 构成。property name 元素引用 JavaBean 属性的名称,而 ref 元素引用另一个 bean 定义的名称。idref 元素之间的这种关联表示协作对象之间的依赖项。有关配置对象的依赖项的详细信息,请参阅Dependencies

In the preceding example, the service layer consists of the PetStoreServiceImpl class and two data access objects of the types JpaAccountDao and JpaItemDao (based on the JPA Object-Relational Mapping standard). The property name element refers to the name of the JavaBean property, and the ref element refers to the name of another bean definition. This linkage between id and ref elements expresses the dependency between collaborating objects. For details of configuring an object’s dependencies, see Dependencies.

Composing XML-based Configuration Metadata

将 Bean 定义跨越多个 XML 文件可能非常有用。通常,每个单独的 XML 配置文件表示架构中的一个逻辑层或模块。

It can be useful to have bean definitions span multiple XML files. Often, each individual XML configuration file represents a logical layer or module in your architecture.

你可以使用 ClassPathXmlApplicationContext 构造函数从 XML 片段加载 Bean 定义。此构造函数采用多个 Resource 位置,如 previous section 中所示。或者,使用一个或多个 <import/> 元素的出现来从其他文件或文件加载 Bean 定义。以下示例显示了如何执行此操作:

You can use the ClassPathXmlApplicationContext constructor to load bean definitions from XML fragments. This constructor takes multiple Resource locations, as was shown in the previous section. Alternatively, use one or more occurrences of the <import/> element to load bean definitions from another file or files. The following example shows how to do so:

<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 位置。如你所见,会忽略前导斜杠。然而,鉴于这些路径是相对路径,所以最好根本不使用斜杠。根据 Spring Schema,要导入的文件的内容(包括顶层 <beans/> 元素)必须是有效的 XML Bean 定义。

In the preceding example, external bean definitions are loaded from three files: services.xml, messageSource.xml, and themeSource.xml. All location paths are relative to the definition file doing the importing, so services.xml must be in the same directory or classpath location as the file doing the importing, while messageSource.xml and themeSource.xml must be in a resources location below the location of the importing file. As you can see, a leading slash is ignored. However, given that these paths are relative, it is better form not to use the slash at all. The contents of the files being imported, including the top level <beans/> element, must be valid XML bean definitions, according to the Spring Schema.

可以使用相对 ../ 路径引用父目录中的文件,但这是不推荐的。这样做相当于创建对当前应用程序外部文件的依赖关系。特别是,不推荐对 classpath: URL(例如,classpath:../services.xml)使用此引用,在这里,运行时解析进程会选择“最近的” classpath 根,然后查找其父目录。Classpath 配置的更改可能会导致选择不同的不正确目录。

It is possible, but not recommended, to reference files in parent directories using a relative "../" path. Doing so creates a dependency on a file that is outside the current application. In particular, this reference is not recommended for classpath: URLs (for example, classpath:../services.xml), where the runtime resolution process chooses the “nearest” classpath root and then looks into its parent directory. Classpath configuration changes may lead to the choice of a different, incorrect directory.

你始终可以使用完全限定资源位置代替相对路径:例如,file:C:/config/services.xmlclasspath:/config/services.xml。不过,需要注意的是,这相当于将应用程序的配置与特定的绝对位置耦合。通常,通过针对运行时 JVM 系统属性解析的 ${…​} 占位符,最 好对这些绝对位置保持间接引用。

You can always use fully qualified resource locations instead of relative paths: for example, file:C:/config/services.xml or classpath:/config/services.xml. However, be aware that you are coupling your application’s configuration to specific absolute locations. It is generally preferable to keep an indirection for such absolute locations — for example, through "${…​}" placeholders that are resolved against JVM system properties at runtime.

命名空间本身提供 import 指令功能。除了纯 Bean 定义之外,Spring 提供的选择 XML 命名空间中还有一些超出范围的配置功能,例如 contextutil 命名空间。

The namespace itself provides the import directive feature. Further configuration features beyond plain bean definitions are available in a selection of XML namespaces provided by Spring — for example, the context and util namespaces.

The Groovy Bean Definition DSL

作为外部化配置元数据的另一个示例,Bean 定义也可以在 Spring 的 Groovy Bean Definition DSL 中表达,如 Grails 框架中所知。通常,此类配置保存在 “.groovy” 文件中,其结构如以下示例所示:

As a further example for externalized configuration metadata, bean definitions can also be expressed in Spring’s Groovy Bean Definition DSL, as known from the Grails framework. Typically, such configuration live in a ".groovy" file with the structure shown in the following example:

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 定义文件。

This configuration style is largely equivalent to XML bean definitions and even supports Spring’s XML configuration namespaces. It also allows for importing XML bean definition files through an importBeans directive.

Using the Container

ApplicationContext 是一个接口,用于具备高级工厂,该工厂能够维护不同 Bean 及其依赖关系的注册表。通过使用 T getBean(String name, Class<T> requiredType) 方法,你可以检索你的 Bean 实例。

The ApplicationContext is the interface for an advanced factory capable of maintaining a registry of different beans and their dependencies. By using the method T getBean(String name, Class<T> requiredType), you can retrieve instances of your beans.

ApplicationContext 让你能够读取 Bean 定义并访问它们,如下所示:

The ApplicationContext lets you read bean definitions and access them, as the following example shows:

  • 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 配置:

With Groovy configuration, bootstrapping looks very similar. It has a different context implementation class which is Groovy-aware (but also understands XML bean definitions). The following example shows Groovy configuration:

  • Java

  • Kotlin

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

最灵活的变体是 GenericApplicationContext,与 Reader 委托一起使用,例如,对于 XML 文件,则与 XmlBeanDefinitionReader 一起使用,如下所示:

The most flexible variant is GenericApplicationContext in combination with reader delegates — for example, with XmlBeanDefinitionReader for XML files, as the following example shows:

  • 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,如下所示:

You can also use the GroovyBeanDefinitionReader for Groovy files, as the following example shows:

  • 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 上混合并匹配此类 Reader 委托,从不同的配置源读取 Bean 定义。

You can mix and match such reader delegates on the same ApplicationContext, reading bean definitions from diverse configuration sources.

然后,你可以使用 getBean 来检索 Bean 实例。ApplicationContext 接口有一些用于检索 Bean 的其他方法,但理想情况下,你的应用程序代码永远不应该使用它们。事实上,你的应用程序代码根本不应调用 getBean() 方法,从而根本不依赖 Spring API。例如,Spring 与 Web 框架的集成针对各种 Web 框架组件(如控制器和 JSF 托管 Bean)提供依赖注入,允许你通过元数据(如自动连接注解)声明对特定 Bean 的依赖关系。

You can then use getBean to retrieve instances of your beans. The ApplicationContext interface has a few other methods for retrieving beans, but, ideally, your application code should never use them. Indeed, your application code should have no calls to the getBean() method at all and thus have no dependency on Spring APIs at all. For example, Spring’s integration with web frameworks provides dependency injection for various web framework components such as controllers and JSF-managed beans, letting you declare a dependency on a specific bean through metadata (such as an autowiring annotation).