6.2 容器概述
代表Spring IoC容器的org.springframework.context.ApplicationContext接口负责实例化、配置和组装上述bean。容器通过读取配置元数据来获取有关要实例化,配置和组装的对象的指令。以XML,Java注释或Java代码形式呈现配置元数据。它允许你表达组成你应用程序的对象以及这些对象之间丰富的相互依赖关系。
ApplicationConext接口的几个实现是与Spring一起提供的。在独立应用程序中,通常会创建ClassPathXmlApplicationContext或FileSystemXmlApplicationContext实例。虽然XML一直是定义配置元数据的传统格式,但你可以通过提供少量XML配置来声明性地支持这些额外的元数据格式,从而指导容器去使用Java注解或代码作为元数据格式。
在大多数应用程序场景中,不要求用明确的用户代码去实例化一个或多数Spring IoC容器实例,例如,在Web应用程序场景中,应用程序web.xml文件中的简单的八行(左右)Web描述符XML样板程序通常就足够了(参考6.15.4章节,“方便的Web应用程序ApplicationContext实例化”)。如果你正在使用的是支持Spring Tool Suite的Eclipse开发环境,只需点击几下鼠标或按键即可轻松创建此样板文件配置。
下图是Spring工作原理的高级视图。应用程序类与配置元数据相结合,以便在创建和初始化ApplicationContext之后,拥有一个完全配置且可执行的系统或应用程序。
图6.1 Spring IoC容器
6.2.1 配置元数据
如上图所示,Spring IoC容器使用了一种配置元数据形式;此配置元数据展现了,你作为应用程序开发人员告诉Spring容器如何在应用程序中去实例化,配置和组装对象。
配置元数据习惯上以简单直观的XML格式提供,本章大部分会使用XML格式去表达Spring IoC容器关键概念和功能。
注意:基于XML元数据并不是配置元数据的唯一方式。Spring IoC容器自身完全从这种配置元数据实际书写的格式解耦了。最近,这么多开发者选择基于Java配置方式来开发Spring应用程序。
关于在Spring容器中使用其他形式元数据,请参阅:
- 基于注解的配置:Spring 2.5引入了对基于注解的配置元数据的支持。
- 基于Java配置:从Spring 3.0开始,Spring JavaConfig项目提供的许多功能都成为Spring Framework核心的一部分。因此,你可以使用Java而不是XML文件在应用程序类外部定义Bean。要使用这些新功能,请参阅@Configuration,@ Bean,@ Import和@DependsOn注解。
Spring配置包含至少一个且通常不止一个由容器管理的Bean的定义。基于XML的配置元数据将这些Bean的配置作为<bean/>元素放在顶级<beans/>元素里面。Java配置则通常在@Configuration类中使用@Bean标记方法。
这些bean定义对应于构成应用程序的实际对象。通常,你定义服务层对象,数据访问层对象(DAO),表示层对象(如Struts Action实例),基础结构对象(如Hibernate SessionFactories,JMS队列等)。通常,不会在容器中配置细粒度域对象,因为创建和加载域对象经常是DAOs和业务逻辑的责任。然而,你可以使用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; 有关更多信息,请参阅依赖项。
6.2.2 实例化容器
实例化Spring IoC容器非常简单。提供给ApplicationContext构造函数的位置路径实际上是允许容器从各种外部资源(如本地文件系统,Java CLASSPATH等)加载配置元数据的资源字符串。
ApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"services.xml", "daos.xml"});
在了解了Spring的IoC容器之后,您可能想要了解有关Spring的Resource抽象的更多信息,如第7章“资源”中所述,它提供了一种从URI语法定义的位置去读取一个InputStream的便捷机制。特别是,用于构建应用程序上下文的Resource路径,如第7.7节“应用程序上下文和资源路径”中所述。
以下示例显示了服务层对象(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对象/关系映射标准)。属性name元素引用JavaBean属性的名称,ref元素引用另一个bean定义的名称。id和ref元素之间的这种联系表达了协作对象之间的依赖关系。有关配置对象的依赖关系的详细信息,请参阅依赖关系。
构建基于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>
在前面的示例中,从这三个文件:services.xml,messageSource.xml和themeSource.xml加载外部bean的定义。所有位置路径都与执行导入的定义文件相关,因此services.xml一定得跟执行导入的文件位于相同的目录或类路径位置上,而messageSource.xml和themeSource.xml必须位于导入文件位置下的resources位置下。如你所见,忽略前面的反斜杠,但考虑到这些路径是相对的,最好不要使用斜杠。根据Spring Schema,被导入的文件的内容(包括顶级<beans />元素)必须是有效的XML bean的定义。
注意:可以(但不建议)使用相对“../”路径引用父目录中的文件。这样做会在当前应用程序之外创建一个文件依赖。特别是,不建议将此引用用于“classpath:”URLs(例如,“classpath:../ services.xml”),在此处,运行时解析过程会选择“最近的”classpath根路径,然后查看其父目录,因此classpath配置更改就可能导致选择不同的、不正确的目录。
你可以始终使用绝对资源路径替代相对路径:例如,“file:C:/config/services.xml”或“classpath:/config/services.xml”。但是,请你注意将应用程序的配置与指定的绝对路径关联起来。通常最好间接地持有这样的绝对路径,例如,使用“$ {...}”占位符,在运行时它会作为JVM系统属性来解析。
6.2.3 使用容器
ApplicationContext是能够维护不同bean及其依赖项的注册表的高级工厂的接口。 使用方法T getBean(String name,Class <T> requiredType),你可以检索bean的实例。
AppliactionContext使你可以读取bean的定义并像如下方式访问它们:
// create and configure beans ApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"services.xml", "daos.xml"}); // retrieve configured instance PetStoreService service = context.getBean("petStore", PetStoreService.class); // use configured instance List<String> userList = service.getUsernameList();
你使用getBean()来检索bean的实例。ApplicationContext接口还有一些其他检索bean的方法,但理想情况下,你的应用程序代码应该永远不会使用它们。实际上,您的应用程序代码再也不会调用getBean()方法,因此,再也不依赖Spring APIs。例如,Spring与Web框架的集成为各种Web框架类(如控制器和JSF托管bean)给你提供了依赖注入。