核心技术-IOC-2

1.2.容器概述

org.springframework.context.ApplicationContext接口负责实例化、配置和组装bean,即可代表Spring IoC容器。容器通过读取配置元数据获得关于实例化、配置和组装哪些对象的指令。配置元数据用XML、Java注释或Java代码表示。它允许您表达组成应用程序的对象以及这些对象之间丰富的相互依赖关系。

Spring提供了几个ApplicationContext接口的实现。在独立的应用程序中,可以使用ClassPathXmlApplicationContextFileSystemXmlApplicationContext。虽然XML是定义配置元数据的传统格式,但是您可以通过提供少量XML配置以声明方式指示容器支持使用Java注释或代码作为元数据格式。

在大多数应用程序场景中,不需要显式的用户代码来创建Spring IoC容器的一个或多个实例。例如,在web应用程序中,一个简单的8行(大约)样板web.xml文件通常就足够了(见Convenient ApplicationContext Instantiation for Web Applications)。如果您使用Spring Tools for Eclipse(一个强大的Eclipse开发环境),只需点击几下鼠标就可以轻松创建这个样板配置。

下图从较高层面展示了Spring是如何工作的。应用程序类与配置元数据相结合,这样在ApplicationContext创建并初始化之后,您就拥有了一个配置完整且可执行的应用程序。

Spring IoC容器

1.2.1.配置元数据

如上图所示,Spring IoC容器需要某种形式的配置元数据。此配置元数据代表了作为应用程序开发人员,您诉Spring容器如何实例化、配置和组装应用程序中的对象。

配置元数据传统上以一种简单而直观的XML格式提供,本章的大部分内容都使用这种格式来描述Spring IoC容器的关键概念和特性。

基于XML的元数据并不是唯一允许的配置元数据形式。Spring IoC容器本身与配置元数据的方式是完全解耦的。现在,许多开发人员为他们的Spring应用程序选择基于java的配置

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

  • Annotation-based configuration:Spring2.5引入了对基于注释的配置元数据的支持。
  • Java-based configuration:从Spring 3.0开始,Spring JavaConfig项目提供的许多特性成为了核心Spring框架的一部分。Starting with Spring 3.0, many features provided by the Spring JavaConfig project became part of the core Spring Framework. 因此,您可以通过使用Java而不是XML文件来定义应用程序类外部的bean。使用这些新特性,请参见@Configuration@Bean@Import@DependsOn注解。

Spring配置由至少一个(通常是多个)被容器管理的bean定义组成。基于XML的配置元数据通过root元素<beans/>中的<bean/>元素来配置。Java配置通常在@Configuration类中使用@Bean注解的方式来配置。

这些bean定义对应应用程序内的实际对象。比如:服务层对象(service)、数据访问层对象(DAO)、表示层对象(如Struts的Action,SpringMVC的Controller),还有一些底层基础设施对象(如Hibernate的SessionFactories、JMS的Queues)等等。通常,不需要在容器中配置细粒度的领域对象(POJO、JavaBean等),因为创建和加载领域对象通常是DAO和service的责任。但是,您可以使用Spring与AspectJ的集成来配置在IoC容器控制之外创建的对象。参见Using AspectJ to dependency-inject domain objects with 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="...">
        <!-- 这个bean的依赖和配置在这里 -->
    </bean>

    <bean id="..." class="...">
        <!-- 这个bean的依赖和配置在这里 -->
    </bean>

    <!-- 更多的bean定义 -->

</beans>
  • id属性是标识单个bean定义的字符串。
  • class属性定义bean的类型并使用完全限定的类名。

id属性的值指向对象。本例中没有关于依赖项的配置示例。更多信息请参见Dependencies

1.2.2.实例化一个容器

在下面示例代码中,提供给ApplicationContext构造函数的路径或路径列表是资源路径字符串,这些资源路径字符串允许容器从各种外部资源(如本地文件系统、Java CLASSPATH等)加载配置元数据。

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

在了解了Spring的IoC容器之后,您可能想了解更多关于Spring的Resource抽象(如参考资料所述),它为从URI语法中定义的路径读取InputStream提供了一种方便的机制。特别是,Resource用于构建应用程序上下文,如Application Contexts and Resource Paths所述。

以下示例显示了服务层对象(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"/>
        <!-- 这个bean的其他依赖和配置在这里 -->
    </bean>

    <!-- 更多的服务层bean定义在这里 -->

</beans>

下面的示例显示了数据访问对象(dao.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">
        <!-- 这个bean的其他依赖和配置在这里 -->
    </bean>

    <!-- 更多数据访问对象的bean定义在这里 -->

</beans>

在上面的例子中,服务层由PetStoreServiceImpl类和JpaAccountDaoJpaItemDao类型的两个数据访问对象组成(基于JPA ORM)。namme元素指的是JavaBean属性的名称,而ref元素指的是另一个bean定义的名称。 idref元素之间的这种链接表示了对象之间的依赖关系。有关配置对象依赖关系的详细信息,请参见Dependencies

组合基于XML的配置

将bean定义拆分成多个XML文件是很有用的。通常,每个单独的XML配置文件代表体系结构中的一个逻辑层或模块。

可以使用ApplicationContext构造函数从所有这些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.xmlmessageSource.xmlthemeSource.xml。所有导入文件路径都相对于执行导入的定义文件,因此services.xml必须与执行导入的文件位于相同的目录或类路径位置,而messageSource.xmlthemeSource.xml必须位于导入文件位置下面的resources目录里。如您所见,前面的斜杠被忽略了。但是,考虑到这些路径是相对的,最好不要使用斜杠。导入的文件的内容(包括顶级<beans/>元素)必须是有效的基于Spring Schema的XML bean定义。

可以使用.. /来引用父目录中的文件,但不建议这样做。这样做将创建对当前应用程序之外的文件的依赖关系。特别是,不建议对classpath:类型的URL(例如,classpath:../services.xml)使用../,因为运行解析过程会选择最近的类路径根,然后查看其父目录。类路径的更改可能导致选择不同的、不正确的目录。

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

命名空间本身提供了导入指令功能。除了普通bean定义之外,Spring提供的XML名称空间中还提供了更多的配置特性——例如,contextutil名称空间。

1.2.3.使用容器

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

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

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

您可以在相同的ApplicationContext上混合使用不同的reader,以从不同的配置源读取bean定义。

然后可以使用getBean来获取bean的实例。ApplicationContext接口有一些其他的方法用于获取bean,但是,理想情况下,应用程序代码不应该使用它们。实际上,您的应用程序代码根本不应该调用getBean()方法,因此也根本不需要依赖于Spring的API。例如,Spring与web框架的集成为各种web框架组件(如controller和JSF bean)提供了依赖注入,允许您通过元数据(如自动装配注解)声明对特定bean的依赖。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,496评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,407评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,632评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,180评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,198评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,165评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,052评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,910评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,324评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,542评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,711评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,424评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,017评论 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,668评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,823评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,722评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,611评论 2 353

推荐阅读更多精彩内容

  • 接下来介绍在Spring Framework中不可或缺的那些技术。 其中最重要的非控制反转(IoC)容器莫属。在介...
    JiinYuu阅读 224评论 0 0
  • spring官方参考文档的这一部分涵盖了Spring框架绝对不可或缺的所有技术。散人闲来无事,做个知识的搬运工。此...
    WalkByte阅读 344评论 0 1
  • 1.2. 容器概述 org.springframework.context.ApplicationContext接...
    远去的青阅读 100评论 0 0
  • (上一篇内容篇幅过多,阅读理解起来比较费力,今后细分小节,形成小篇幅阅读) 1.3 Bean Overview (...
    WalkByte阅读 190评论 0 1
  • 我是黑夜里大雨纷飞的人啊 1 “又到一年六月,有人笑有人哭,有人欢乐有人忧愁,有人惊喜有人失落,有的觉得收获满满有...
    陌忘宇阅读 8,535评论 28 53