容器概述
cn.taketoday.context.ApplicationContext
接口代表了 IoC 容器,
负责实例化、配置和组装 bean。容器通过读取配置元数据来获取实例化、配置和组装对象的指令。
配置元数据可以用 XML、Java 注解或 Java 代码表示。它允许您表达组成应用程序的对象以及这些对象之间的丰富相互依赖关系。
框架提供了几个 ApplicationContext
接口的实现,在单体应用中,当你要使用 XML 配置来描述和配置 Bean 时
你可以使用 ClassPathXmlApplicationContext
或者 FileSystemXmlApplicationContext
。
当然你也可以使用少量 XML 配置开启 Java 注解或代码作为元数据格式。
Configuration Metadata
IoC 容器消耗一种形式的配置元数据。这些配置元数据代表您作为应用程序开发者告诉 Infra 容器如何实例化、配置和组装应用程序中的对象。
传统上,配置元数据通常以简单直观的 XML 格式提供,这也是本章大部分内容用来传达 IoC 容器的关键概念和特性的方式。
XML 格式的元数据配置并不是唯一允许的配置元数据形式。IoC 容器本身与配置元数据的实际编写格式完全解耦。 如今,许多开发者选择使用 Java-based configuration 来配置他们的 Infra 应用程序。 |
有关在 Infra 容器中使用其他形式的元数据的信息,请参阅:
-
基于注解的配置: 使用基于注解的配置元数据定义 bean。
-
基于 Java 的配置: 使用 Java 而不是 XML 文件在应用程序类外部定义 bean。要使用这些功能,请参阅
@Configuration
,@Bean
,@Import
, 和@DependsOn
注解.
基础设施配置至少包括一个,通常是多个 bean 定义,容器必须管理这些定义。基于 XML 的配置元数据将这些 bean 配置为顶级
<beans/>
元素内的 <bean/>
元素。Java 配置通常使用 @Configuration
类中的 @Bean
注释方法。
这些 bean 定义对应于组成应用程序的实际对象。通常,您定义服务层对象、持久化层对象(如存储库或数据访问对象(DAO))、
表示层对象(如 Web 控制器)、基础设施对象(如 JPA EntityManagerFactory
、JMS 队列等)。通常,不会在容器中配置细
以下示例显示了基于 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。有关更多信息,
请参阅 Dependencies。
实例化一个容器
ApplicationContext
构造函数中提供的位置路径或路径是资源字符串,允许容器从各种外部资源加载配置元数据,例如本地文件系统、Java CLASSPATH
等等。
ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");
在了解了 Infra IoC 容器之后,您可能想进一步了解 Infra |
下面的示例显示了服务层对象(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="cn.taketoday.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="cn.taketoday.samples.jpetstore.dao.jpa.JpaAccountDao">
<!-- additional collaborators and configuration for this bean go here -->
</bean>
<bean id="itemDao" class="cn.taketoday.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
元素之间的这种关联表示了协作对象之间的依赖关系。
有关配置对象依赖关系的详细信息,请参阅 Dependencies。
组合基于 XML 的配置元数据
可以将Bean定义跨越多个XML文件是非常有用的。通常,每个独立的XML配置文件代表着架构中的一个逻辑层或模块。
您可以使用应用程序上下文构造函数从所有这些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
目录下。
正如您所看到的,前导斜杠会被忽略。但是,鉴于这些路径是相对的,最好根本不使用斜杠。被导入文件的内容,包括顶级 <beans/>
元素,
必须符合 Infra Schema 的有效 XML Bean 定义。
可以使用相对 "../" 路径引用父目录中的文件,但不推荐这样做。这样做会创建对当前应用程序之外的文件的依赖关系。
特别是,不建议在 您始终可以使用完全限定的资源位置而不是相对路径:例如, |
命名空间本身提供了导入指令功能。除了普通的 Bean 定义之外,Infra 提供的一些 XML
命名空间还提供了进一步的配置功能,例如 context
和 util
命名空间。
使用容器
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();
ApplicationContext context = new GenericGroovyApplicationContext("services.groovy", "daos.groovy");
最灵活的变体是 GenericApplicationContext
与读取代理结合使用,例如,使用 XmlBeanDefinitionReader
读取 XML 文件,如下面的示例所示:
GenericApplicationContext context = new GenericApplicationContext();
new XmlBeanDefinitionReader(context).loadBeanDefinitions("services.xml", "daos.xml");
context.refresh();
您可以在同一个 ApplicationContext
中混合使用这样的读取代理,从不同的配置源中读取 Bean 定义。
然后,您可以使用 getBean
方法检索您的 bean 的实例。ApplicationContext
接口还有一些其他用于检索 bean 的方法,
但理想情况下,您的应用程序代码不应使用它们。事实上,您的应用程序代码根本不应调用 getBean()
方法,因此完全不依赖 Infra APIs。
例如,Infra 与 Web 框架的集成提供了对各种 Web 框架组件(如控制器和 JSF 管理的 bean)的依赖注入,
使您可以通过元数据(例如自动装配注解)声明对特定 bean 的依赖关系。