容器概述
org.springframework.context.ApplicationContext
接口表示 Spring IoC 容器,负责实例化、配置和组装 Bean。容器通过读取配置元数据获取有关要实例化、配置和组装的组件的指令。配置元数据可以表示为带注解的组件类、带有工厂方法的配置类或外部 XML 文件或 Groovy 脚本。使用任何一种格式,您都可以组合您的应用程序以及这些组件之间丰富的相互依赖关系。
核心 Spring 包含 ApplicationContext
接口的多个实现。在独立应用程序中,通常会创建 AnnotationConfigApplicationContext
或 ClassPathXmlApplicationContext
的实例。
在大多数应用程序场景中,不需要显式用户代码来实例化一个或多个 Spring IoC 容器实例。例如,在普通的 Web 应用程序场景中,应用程序的 web.xml
文件中一个简单的样板 Web 描述符 XML 就足够了(请参阅 Web 应用程序的便捷 ApplicationContext 实例化)。在 Spring Boot 场景中,应用程序上下文会根据常见的设置约定为您隐式引导。
下图显示了 Spring 工作原理的高级视图。您的应用程序类与配置元数据组合在一起,以便在创建和初始化 ApplicationContext
后,您将拥有一个完全配置且可执行的系统或应用程序。
配置元数据
如上图所示,Spring IoC 容器使用某种形式的配置元数据。此配置元数据表示您(作为应用程序开发人员)如何告诉 Spring 容器实例化、配置和组装应用程序中的组件。
Spring IoC 容器本身与实际编写此配置元数据的格式完全解耦。如今,许多开发人员选择 基于 Java 的配置 来构建他们的 Spring 应用程序
-
基于注解的配置:在应用程序的组件类上使用基于注解的配置元数据定义 Bean。
-
基于 Java 的配置:使用基于 Java 的配置类在应用程序类外部定义 Bean。要使用这些功能,请参阅
@Configuration
、@Bean
、@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="..."> (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。有关更多信息,请参阅 依赖项。
要实例化容器,需要将 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"/>
<import resource="/resources/themeSource.xml"/>
<bean id="bean1" class="..."/>
<bean id="bean2" class="..."/>
</beans>
在前面的示例中,外部 Bean 定义从三个文件加载:services.xml
、messageSource.xml
和 themeSource.xml
。所有位置路径都相对于执行导入的文件,因此 services.xml
必须与执行导入的文件位于同一目录或类路径位置,而 messageSource.xml
和 themeSource.xml
必须位于导入文件位置下的 resources
位置。如您所见,开头的斜杠将被忽略。但是,鉴于这些路径是相对的,最好根本不使用斜杠。根据 Spring 架构,被导入的文件的内容(包括顶级 <beans/>
元素)必须是有效的 XML Bean 定义。
可以使用相对路径“../”引用父目录中的文件,但这不建议这样做。这样做会创建对应用程序外部文件的依赖关系。特别是,不建议对 您可以始终使用完全限定的资源位置代替相对路径:例如, |
命名空间本身提供了 import 指令功能。除了普通 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 的依赖关系。