容器概述
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 容器
image::container-magic.png[]
配置元数据
如上图所示,Spring IoC 容器使用一种配置元数据。此配置元数据代表您作为应用程序开发人员如何告诉 Spring 容器实例化、配置和组装应用程序中的组件。
Spring IoC 容器本身与实际编写此配置元数据的格式完全解耦。如今,许多开发人员为其 Spring 应用程序选择 基于 Java 的配置:
-
基于注解的配置:使用应用程序组件类上的基于注解的配置元数据定义 bean。
-
基于 Java 的配置:通过使用基于 Java 的配置类,在应用程序类外部定义 bean。要使用这些功能,请参阅
@Configuration、https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/annotation/Bean.html[@Bean]、https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/annotation/Import.html[@Import] 和@DependsOn注解。
Spring 配置至少包含一个(通常是多个)容器必须管理的 bean 定义。Java 配置通常在 @Configuration 类中使用 @Bean 注解方法,每个方法对应一个 bean 定义。
这些 bean 定义对应于构成您应用程序的实际对象。通常,您定义服务层对象、持久层对象(例如存储库或数据访问对象 (DAO))、表示层对象(例如 Web 控制器)、基础设施对象(例如 JPA EntityManagerFactory、JMS 队列)等等。通常,不会在容器中配置细粒度的领域对象,因为创建和加载领域对象通常是存储库和业务逻辑的职责。
XML 作为外部配置 DSL
基于 XML 的配置元数据将这些 bean 配置为顶级 <beans/> 元素内的 <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="..."> [id="CO1-1"]1 [id="CO1-2"]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。有关更多信息,请参阅 依赖项。
为了实例化容器,需要将 XML 资源文件的位置路径或路径提供给 ClassPathXmlApplicationContext 构造函数,该构造函数允许容器从各种外部资源(例如本地文件系统、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/> 元素,必须是有效的 XML bean 定义,符合 Spring Schema。
|
可以使用相对的 "../" 路径引用父目录中的文件,但不推荐这样做。这样做会创建对当前应用程序外部文件的依赖。特别是,不建议对 |
命名空间本身提供了导入指令功能。除了纯 bean 定义之外,Spring 提供的一系列 XML 命名空间中还提供了更多配置功能——例如,context 和 util 命名空间。
Groovy Bean 定义 DSL
作为外部化配置元数据的进一步示例,bean 定义也可以在 Spring 的 Groovy Bean 定义 DSL 中表达,这在 Grails 框架中众所周知。通常,此类配置位于具有以下示例所示结构的 ".groovy" 文件中:
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 定义文件。
使用容器
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 与读取器委托结合使用——例如,与 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()
您还可以将 GroovyBeanDefinitionReader 用于 Groovy 文件,如下例所示:
-
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 的依赖。