[TOC]
### 1.2. 容器概述
接口 *org.springframework.context.ApplicationContext* 代表Spring IoC容器,并负责实例化、配置和组装上述beans。容器通过读取配置元数据获取需要实例化、配置和组装的对象的指示信息。配置元数据用XML,Java注解或Java代码表示。它允许你展示组成你的应用程序的对象以及这些对象之间丰富的相互依赖关系。
Spring提供了几个 *ApplicationContext* 开箱即用的接口实现。在独立应用程序中,通常会创建 *ClassPathXmlApplicationContext* 或 *FileSystemXmlApplicationContext* 的实例。虽然XML是用于定义配置元数据的传统格式,但您可以通过提供少量的XML配置来指示容器使用Java注解或代码作为元数据格式,以声明方式支持这些其他元数据格式。
在大多数应用场景中,实例化Spring IoC容器的一个或多个实例不需要显式的用户代码。例如,在Web应用程序场景中,应用程序的web.xml文件中简单的8行(或多行)web样板XML描述符就足够了。如果您使用的是Spring工具套件Eclipse驱动的开发环境,则只需点击几下鼠标或按键即可轻松创建此样板配置。
下图是Spring如何工作的高级视图。您的应用程序类与配置元数据相结合,则在创建并初始化 *ApplicationContext* 之后,您拥有完全配置且可执行的系统或应用程序。
:-: ![The Spring IoC container](https://box.kancloud.cn/5ab6e3c3c7c024947945a20841bd20ea_498x296.png)
#### 1.2.1. 配置元数据
如上图所示,Spring IoC容器使用一种配置元数据的形式;此配置元数据表示作为应用程序开发人员如何告诉Spring容器在您的应用程序中实例化、配置和组装对象。
传统上,配置元数据是以简单直观的XML格式提供的,这是本章大部分内容用来传达Spring IoC容器的关键概念和功能的格式。
>[info] 基于XML的元数据不是唯一允许的配置元数据形式。Spring IoC容器本身与配置元数据实际使用格式完全分离。现在很多开发人员在他们的Spring应用程序中选择基于Java的配置。
有关在Spring容器中使用其他形式的元数据的信息,请参阅:
- 基于注解的配置:Spring 2.5引入了对基于注解的配置元数据的支持。
- 基于Java的配置:从Spring 3.0开始,Spring JavaConfig项目提供的许多功能成为核心Spring框架的一部分。因此,您可以使用Java而不是XML文件来定义应用程序类外部的Beans。要使用这些新功能,请参阅@Configuration,@Bean,@Import和@DependsOn注解。
Spring配置由的至少一个,通常是多个bean定义组成,这些bean容器必须管理。基于XML的配置元数据用\ <bean
/> 元素作为beans的配置,并放置在顶级\<beans />元素内。Java配置通常使用由@Bean注解的方法,该方法位于@Configuration 注解的类中。
这些bean定义对应于组成应用程序的实际对象。通常,您可以定义服务层对象,数据访问对象(DAOs),Struts Action实例等表示层对象,Hibernate SessionFactories等基础结构对象,JMS队列等。通常,不会在容器中配置细粒度的域对象,因为创建和加载域对象通常是DAO和业务逻辑的责任。但是,您可以使用Spring与AspectJ的集成来配置在IoC容器控制之外创建的对象。请参阅 **使用AspectJ依赖注入Spring使用的域对象**。
以下示例显示了基于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
http://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的类型并使用完全限定的类名。id属性的值是指协作对象。本示例中未显示用于引用协作对象的XML;有关更多信息,请参阅**依赖关系**。
#### 1.2.2. 实例化容器
实例化Spring IoC容器很简单。提供给 *ApplicationContext* 构造函数的位置路径实际上是资源字符串,它允许容器从各种外部资源(例如本地文件系统,Java CLASSPATH等等)加载配置元数据。
~~~
ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");
~~~
>[info] 在了解了Spring的IoC容器之后,您可能想了解更多关于Spring的资源抽象的知识,如参考资料中所述,它提供了一种从URI语法中定义的位置读取InputStream的方便机制。特别是,资源路径用于构建应用程序上下文,如 **应用程序上下文和资源路径中** 所述。
以下示例显示服务层对象(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
http://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
http://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配置文件都代表了架构中的逻辑层或模块。
您可以使用应用程序上下文构造函数从所有这些XML片段中加载bean定义。这个构造函数有多个资源位置,如前一节所示。或者,使用一个或多个\<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必须位于导入文件位置下下层的位置。正如你所看到的,一个前导斜线被忽略,但是鉴于这些路径是相对的,最好不要使用斜线。根据Spring Schema,导入的文件的内容(包括顶级\<beans />元素)必须是有效的XML bean定义。
>[info] 可以但不推荐使用“../”这样的相对路径引用父目录中的文件。这样做会创建对当前应用程序外部的文件的依赖关系。特别是,不建议将此方法用于“classpath:”URLs(例如“classpath:../ services.xml”),来在运行时解析过程中选择“最近”的classpath根,然后查看其父目录。Classpath 配置更改可能会导致选择不同的,不正确的目录。
>
> 您始终可以使用完全限定的资源位置而不是相对路径:例如,“file:C:/config/services.xml”或“classpath:/config/services.xml”。但是,请注意,您将应用程序的配置与特定绝对位置相关联。通常最好保持这种绝对位置的间接性,例如通过在运行时根据JVM系统属性解析的“$ {...}”占位符。
import指令是由beans名称空间本身提供的一项功能。除了普通bean定义以外的其他配置特性在由Spring提供的XML名称空间的selection是可用的,例如,“context”和“util”命名空间。
##### Groovy Bean Definition DSL
作为外部化配置元数据的另一个例子,bean的定义也可以在Spring的Groovy Bean Definition 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定义文件。
#### 1.2.3. 使用容器
*ApplicationContext* 是高级工厂的接口,能够维护不同Beans及其依赖项的注册表。使用方法 *T getBean (String name, Class \<T> requiredType)* 方法,可以检索beans的实例。
*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();
~~~
使用Groovy配置,引导看起来非常相似,只是一个不同的上下文实现类,它可以感知Groovy(但也理解XML bean定义):
~~~
ApplicationContext context = new GenericGroovyApplicationContext("services.groovy", "daos.groovy");
~~~
最灵活的变体是GenericApplicationContext与 reader 委派组合,例如,使用读取XML文件的 *XmlBeanDefinitionReader*:
~~~
GenericApplicationContext context = new GenericApplicationContext();
new XmlBeanDefinitionReader(context).loadBeanDefinitions("services.xml", "daos.xml");
context.refresh();
~~~
或者使用Groovy文件的 *GroovyBeanDefinitionReader*:
~~~
GenericApplicationContext context = new GenericApplicationContext();
new GroovyBeanDefinitionReader(context).loadBeanDefinitions("services.groovy", "daos.groovy");
context.refresh();
~~~
如果需要,这样的reader委派可以在同一个 *ApplicationContext* 上混合和匹配,从不同的配置源读取bean定义。
然后可以使用 *getBean* 来检索beans的实例。*ApplicationContext* 接口还有其他一些检索beans的方法,但理想情况下,应用程序代码不应该使用它们。事实上,你的应用程序代码根本不应该调用 *getBean()* 方法,因此完全不依赖于Spring API。例如,Spring与Web框架的集成为各种Web框架组件(如控制器和JSF托管的Beans)提供了依赖注入,允许您通过元数据(例如自动装配注解)声明对特定Bean的依赖关系。