目录
1、容器的概念
2、如何配置元数据
3、如何实例化一个容器
4、使用容器
1、容器的概念
ApplicationContext 代表 Spring IoC 容器,它负责 Spring Beans 的实例化、配置和组装。容器通过读取配置元数据(//配置文件)获取关于要实例化、配置和组装哪些对象的指令。配置元数据可以用 XML、Java 注释或 Java 代码表示。通过配置文件可以定义组成应用程序的对象以及这些对象之间复杂的依赖关系。// 容器通过配置文件来定义 Bean 的创建
Spring 提供了 ApplicationContext 接口的几个实现,例如 ClassPathXmlApplicationContext 和 FileSystemXmlApplicationContext,虽然 XML一直是配置元数据的传统方式,但是也可以指示 Spring 容器使用 Java 注释或 Java 代码作为配置元数据的方式,不过,这也需要借助少量 XML 配置,以声明的方式启用对这些额外元数据格式的支持。// 配置文件可以有多种格式 xml、java 注释、java 代码
在大多数应用程序场景中,不需要显式的去创建 Spring IoC 容器的实例。例如,在 web 应用程序场景中,通常只需要一个简单的 web.xml 样板配置文件就足够了。这个 xml 文件非常简单,大概只有 8 行的样子(web.xml文件)。如果你使用 Spring Tools for Eclipse,创建这样的样板配置将会更加简单。// 大多数场景,不需要显式的去实例化 Spring IoC 容器,那又是怎么实例化的呢?
下图显示了 Spring 如何工作的高级视图。应用程序的类与配置元数据相结合,当 ApplicationContext 通过配置元数据创建并初始化 Beans 之后,就拥有了一个基于配置的和可执行的应用程序。
2、如何配置元数据
如上图所示,Spring IoC 容器使用配置元数据创建对象。该配置元数据的作用就是定义 Spring 容器如何实例化、配置和组装应用程序中的对象。
xml 文件是 Spring 传统的配置文件,虽然 xml 配置文件逐渐被 java 配置文件所代替,但文章中大部分例子还是会用到 xml 文件的配置形式。其他格式的配置文件方式可参考:
Spring 容器的配置文件通常由一个或多个 Bean 定义组成(容器管理 Bean),基于 xml 的配置元数据将这些 bean 配置为顶层 <beans/> 标签中的 <bean/> 元素。而基于 Java 代码的配置通常在 @Configuration 类中使用 @ bean 注释来定义一个 bean。// 如何定义一个 bean
bean 定义与组成应用程序的实际对象层一一对应。比如,定义服务层对象、数据访问层对象(dao)、表示层对象(如 Struts Action 实例)、基础结构对象(如 Hibernate SessionFactories、JMS 队列等)。但是,一般都不需要在容器中配置非常细粒度的域对象(//具体的用户对象,如用户A\B\C),因为创建和加载域对象通常是 dao 和业务逻辑层的责任。另外,也可以使用 Spring 与 AspectJ 的集成来配置在 IoC 容器控制之外创建的对象。// IoC 容器控制之外的对象,AOP 是管理还是配置?如何配置的?
下面的例子展示了基于 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="...">
<!-- 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 的类型,并使用完全限定的类名。
3、如何实例化一个容器
提供给 ApplicationContext 构造函数位置路径或资源字符串路径,允许容器从各种外部资源加载配置元数据,例如本地文件系统、Java ClassPath 等等。// 显示的创建了容器,通过指定文件路径加载配置资源
ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");
下面的示例显示了服务层对象( 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 文件
<?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">
<!-- 此bean的其他配置和属性配置在这里 -->
</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 配置文件代表体系结构中的一个逻辑层或模块。
你可以使用 ApplicationContext 构造函数从所有这些分开的 XML 配置文件中加载 bean 定义。因为 ApplicationContext 构造函数可以接受多个 Resource 位置作为参数。或者,使用 <import/> 标签也可以从一个或多个配置文件中加载 bean 定义。下面的例子展示了如何做到这一点: // 加载多个配置文件的两种方式,其中 import 在Spring boot 中被广泛使用
<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。所有位置路径都是相对于执行导入的定义文件(//定义<import/> 标签的文件)来定义位置的,因此,services.xml 必须与执行导入的文件位于相同的目录或类路径位置,messageSource.xml 和 themeSource.xml 必须位于导入文件位置以下的资源位置。如你所见,前面的斜杠被忽略了。然而,考虑到这些路径是相对的,最好完全不使用斜杠。根据Spring Schema,导入的文件的内容(包括顶层 <beans/> 元素)必须是有效的 XML bean 定义。// 配置文件位置定义有多种形式,同时 xml 配置文件内容有严格的格式规定
可以(但不建议)使用相对路径 “../” 引用父目录中的文件,因为这样做会创建对当前应用程序之外的文件的依赖。特别是,不建议对类路径:URLs(例如,classpath:../services.xml )使用此引用,在这种情况下,运行时解析过程将选择“最近的”类路径根目录,然后查找它的父目录。类路径的更改可能导致选择不同的、错误的目录。// 类移动了,父目录也跟着改变,但是资源文件位置没有改变,导致程序读不到资源文件
推荐使用完全绝对路径而不是相对路径,比如 file:C:/config/services.xml 或者 classpath:/config/services.xml。但是,请注意,这样会将应用程序的配置耦合到特定的绝对位置。对于这种绝对位置,一般最好使用一个间接的方向,例如,使用在运行时根据 JVM 系统属性解析的 “${…}” 占位符。// 使用绝对位置时,通过占位符来进行配置
命名空间本身提供了导入指令特性。除了普通 bean 定义之外,在 Spring 提供的 XML 名称空间选择中还提供了更多的配置特性,比如,context 和 util 命名空间。// 这些是啥?应该不重要?
4、使用容器
ApplicationContext 是一个高级的 Bean 工厂,维护了不同 bean 的注册表和他们之间的依赖关系。通过使用方法 T getBean (字符串名称,Class<T> requiredType),可以获取到 bean 的实例。// getBean() 获取容器中的实例
ApplicationContext 允许你读取 bean 定义并访问它们,如下面的示例所示:
// 创建和配置 beans
ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");
// 获取配置的实例
PetStoreService service = context.getBean("petStore", PetStoreService.class);
// 使用配置的实例
List<String> userList = service.getUsernameList();
最灵活的 ApplicationContext 变体是 GenericApplicationContext 的读取委派,例如,使用XmlBeanDefinitionReader 用于读取 XML 配置文件,如下例所示:
// 通用上下文
GenericApplicationContext context = new GenericApplicationContext();
// Reader 读取器
new XmlBeanDefinitionReader(context).loadBeanDefinitions("services.xml", "daos.xml");
// 刷新上下文
context.refresh();
你也可以为 Groovy 文件使用 GroovyBeanDefinitionReader,如下面的例子所示:
GenericApplicationContext context = new GenericApplicationContext();
// Groovy 文件读取器
new GroovyBeanDefinitionReader(context).loadBeanDefinitions("services.groovy", "daos.groovy");
// 刷新上下文
context.refresh();
通过这种方式可以在同一个 ApplicationContext 上混合和匹配阅读器委托,从不同的配置源读取 bean 定义。// 使用阅读器委托可以从不同类型文件中读取 bean 定义
虽然 ApplicationContext 接口提供一些用于获取 bean 的方法,用户可以使用 getBean 获取 bean 的实例,但通常情况下,应用程序代码不应该使用它们。实际上,应用程序代码也完全没有对 getBean() 方法的调用,完全不依赖 Spring API 。例如,Spring 与 web 框架集成,为各种 web框架组件(如控制器和 jsf 管理的 bean )提供了依赖注入,允许你通过元数据(例如自动装配注释)声明对特定 bean 的依赖。// 自动注入,那么 Spring 如何进行自动注入的呢?