1.2.容器概述

org.springframework.context.ApplicationContext 接口代表了Spring的IoC容器,并负责实例化、配置和组装bean。容器通过读取配置元数据来获取关于实例化、配置和组装哪些对象的指令。配置元数据以XML、Java注解或Java代码的形式表示。它使您能够表达构成您应用程序的对象及其之间的丰富依赖关系。

Spring提供了多种ApplicationContext接口的实现。在独立应用程序中,通常会创建ClassPathXmlApplicationContext或FileSystemXmlApplicationContext的实例。尽管XML一直是定义配置元数据的传统格式,但您可以通过提供少量的XML配置来声明式地启用对Java注解或代码作为元数据格式的支持,从而指示容器使用这些格式。

在大多数应用程序场景中,不需要显式的用户代码来实例化一个或多个Spring IoC容器。例如,在Web应用程序场景中,在应用程序的web.xml文件中通常只需要几行(大约八行左右)标准的Web描述符XML就足够了(详见《Web应用程序的便捷ApplicationContext实例化》)。如果您使用的是Spring Tools for Eclipse(一个基于Eclipse的开发环境),只需几次鼠标点击或按键就可以轻松创建这种标准配置。

以下图表展示了Spring工作原理的高层次视图。您的应用程序类与配置元数据相结合,因此,在ApplicationContext被创建并初始化之后,您就拥有了一套完全配置且可执行的系统或应用程序。

图1. Spring的IoC容器

1.2.1.配置元数据

如上图所示,Spring的IoC容器消耗一种配置元数据。这种配置元数据表示了您作为应用程序开发者,如何告诉Spring容器实例化、配置以及组装您应用程序中的对象。

配置元数据传统上是以简单直观的XML格式提供的,这也是本章大部分内容用来传达Spring IoC容器关键概念和特性的方式。

基于XML的元数据并不是唯一允许的配置元数据形式。Spring的IoC容器本身与这种配置元数据的实际书写格式是完全解耦的。如今,许多开发人员为他们的Spring应用程序选择了基于Java的配置。

有关使用其他形式的元数据与Spring容器一起的信息,请参见:

  • 基于注解的配置:Spring 2.5引入了对基于注解的配置元数据的支持。
  • 基于Java的配置:从Spring 3.0开始,Spring JavaConfig项目所提供的许多功能成为了核心Spring框架的一部分。因此,您可以使用Java而不是XML文件来定义应用程序类之外的bean。要使用这些新特性,请参见@Configuration、@Bean、@Import 和 @DependsOn 注解。

Spring配置至少包含一个并且通常包含多个容器必须管理的bean定义。基于XML的配置元数据将这些bean配置为顶层元素内的元素。Java配置通常使用在一个@Configuration类中的@Bean注解的方法。

这些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        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的类型,并使用完全限定的类名。

id属性的值指的是协作对象。本示例中未显示引用协作对象的XML。更多信息请参见《依赖》部分。

1.2.2.实例化一个容器

提供给ApplicationContext构造函数的位置路径或路径集合是资源字符串,它们使得容器可以从各种外部资源(如本地文件系统、Java CLASSPATH等)加载配置元数据。

JAVA

ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");

Kotlin

val context = ClassPathXmlApplicationContext("services.xml", "daos.xml")

在了解了Spring的IoC容器之后,您可能还想了解更多关于Spring的Resource抽象的信息(如《Resource资源》一节中所述),它提供了一种从URI语法定义的位置读取InputStream的便捷机制。特别是,Resource路径用于构建应用程序上下文,如《应用程序上下文和Resource路径》一节中所述。

以下示例展示了服务层对象(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配置文件代表了架构中的一个逻辑层或模块。

您可以使用应用程序上下文构造器从所有这些XML片段中加载bean定义。这个构造器接受多个资源位置,如前一节所示。或者,使用一个或多个元素从另一个文件或多个文件中加载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 架构有效的 XML bean 定义。

可以,但不推荐使用相对的 "../" 路径来引用父目录中的文件。这样做会产生对当前应用程序之外文件的依赖。特别是,这种引用方式不推荐用于 classpath: URL(例如,classpath:../services.xml),因为在运行时解析过程中会选择“最近”的类路径根目录,然后再查找其父目录。类路径配置的更改可能导致选择了一个不同的、错误的目录。

您可以始终使用完全限定的资源位置而不是相对路径:例如,file:C:/config/services.xml 或 classpath:/config/services.xml。但是,请注意,这样做会使您的应用程序配置与特定的绝对位置耦合。通常,最好是保持对这些绝对位置的间接引用——例如,通过 "${...}" 占位符,这些占位符将在运行时解析为JVM系统属性。

Groovy语言编写的Bean定义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 是一个高级工厂的接口,能够维护不同bean及其依赖关系的注册表。通过使用方法 `getBean(String name, Class requiredType)`,您可以检索bean的实例。

ApplicationContext 允许您读取bean定义并访问它们,如下例所示:

JAVA

// 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();

 Kotlin

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

ApplicationContext context = new GenericGroovyApplicationContext("services.groovy", "daos.groovy");

Kotlin

val context = GenericGroovyApplicationContext("services.groovy", "daos.groovy")

最灵活的变体是结合使用reader委托的GenericApplicationContext——例如,对于XML文件,可以与XmlBeanDefinitionReader一起使用,如下例所示:

Java

GenericApplicationContext context = new GenericApplicationContext();
new XmlBeanDefinitionReader(context).loadBeanDefinitions("services.xml", "daos.xml");
context.refresh();

Kotlin

val context = GenericApplicationContext()
GroovyBeanDefinitionReader(context).loadBeanDefinitions("services.groovy", "daos.groovy")
context.refresh()
val context = GenericApplicationContext()
XmlBeanDefinitionReader(context).loadBeanDefinitions("services.xml", "daos.xml")
context.refresh()

您也可以使用GroovyBeanDefinitionReader来处理Groovy文件,如下例所示:

JAVA

GenericApplicationContext context = new GenericApplicationContext();
new GroovyBeanDefinitionReader(context).loadBeanDefinitions("services.groovy", "daos.groovy");
context.refresh();

Kotlin

val context = GenericApplicationContext()
GroovyBeanDefinitionReader(context).loadBeanDefinitions("services.groovy", "daos.groovy")
context.refresh()

您可以在一个相同的ApplicationContext中混合使用这些reader委托,从不同的配置来源读取bean定义。

然后,您可以使用getBean方法来检索您的bean实例。ApplicationContext接口还有一些其他用于检索bean的方法,但是理想情况下,您的应用程序代码不应该使用它们。事实上,您的应用程序代码根本不应该调用getBean()方法,也不应该对Spring API有任何依赖。例如,Spring与Web框架的集成提供了对各种Web框架组件(如控制器和JSF托管bean)的依赖注入,这让您可以声明对特定bean的依赖(例如,通过自动装配注解这样的元数据)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值