Spring参考手册 2 核心技术

翻译自Spring官方文档 4.1.2版本

一、IoC容器

1.1 Spring IoC容器和beans简介

这个章节涵盖了Spring Framework<em>控制反转</em>(Inversion of Control 缩写IoC)的原理。IoC也被称为依赖注入(dependency injection)。它是一个流程由此对象定义他们的依赖,也就是说,定义与某个对象一起工作的其他对象,只有通过构造器参数、工厂方法的参数或者将属性通过set到它被构造后或从一个工厂方法返回后的对象实例 。当容器创建bean时会<em>注入</em>(injects )那些依赖。相对于bean自己来控制其依赖的实例化或位置的做法,这个过程从根本上是反转的,因此叫做<em>控制反转。</em>

org.springframework.beansorg.springframework.context这两个包是Spring框架的IoC容器的基础。BeanFactory接口提供了一个先进的能够配置的机制来管理任何类型的对象。ApplicationContextBeanFactory的一个子接口。它使以下几个方面更容易集成:Spring AOP特性、消息资源处理(用来国际化)、事件发布、应用层特殊的上下文比如用在web应用程序的WebApplicationContext

在Spring里,组成你应用程序骨干的对象并且被Spring IoC容器管理,它们被称作beans(这个词相当难翻译)。一个bean是一个已经实例化的、组装的除此之外还是被Spring IoC容器管理的对象。beans和它们之间的依赖关系反映在一个容器使用的<em>配置元数据</em>(configuration metadata)里。

1.2 容器概览

org.springframework.context.ApplicationContext这个接口代表了Spring IoC容器,并且还负责实例化、配置和装配前面提到的beans。容器获取其有关哪些对象实例化的说明,设置、然后通过读取配置元数据装配beans。配置元数据被表现在XML、Java annotations或者Java code。它允许你去表达构成你的应用程序的对象并且丰富这些对象间的依赖关系。

有几个ApplicationContext接口的实现提供开箱即用(out-of-the-box )的功能。在独立的应用程序通常会创建一个ClassPathXmlApplicationContext或者FileSystemXmlApplicationContext的实例。虽然XML已经成为传统的形式来定义配置元数据,你还可以指示容器来使用Java annotations或者code作为元数据的形式但是仍旧需要一小段XML配置来声明启动这些额外元数据形式的支持。

在绝大多数应用程序的场景里,显式的用户代码不需要去实例化一个或多个Spring IoC容器。例如,在web应用程序场景中,在web.xml文件中几行简单的配置就通常足够了。

1.2.1 配置元数据

如上图所示,Spring IoC容器消费了一份配置元数据,配置元数据表示你作为一名程序开发者告诉Spring容器去实例化、设置和装配哪些对象。

Spring 2.5开始引进基于注解来配置元数据的支持。

Spring 3.0开始支持基于JavaConfig来配置元数据。

Spring配置至少包含一个(通常都是多个)容器必须管理的bean定义。基于XML的配置元数据显示了这些bean被配置为bean元素,而它在一个顶级元素beans下。Java类的配置方式通常使用@Bean注解在方法上,方法所在的类使用@Configuration注解。

这些bean定义对应组成你应用程序真实的对象。通常你会定义服务层的对象;数据访问对象(DAOs);展示对象(presentation objects)例如,Struts Action接口;基础结构对象(infrastructure objects)例如,Hibernate SessionFactories;JMS Queues等等。通常有一个没有在容器里配置为bean的域对象(domain objects),因为这通常是DAOs和业务逻辑来创建和加载域对象。但是你可以用Spring集成的AspectJ来配置这些在IoC容器控制范围外被创建的对象。

下面的例子展示了基于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的类型并且使用完全限定类名(fully qualified classname)。

1.2.2 实例化一个容器

实例化一个Spring IoC是很容易的。一个路径或者多个路径提供给ApplicationContext的构造函数允许容器从多种多样的外界资源加载配置元数据 ,例如本地文件系统、从java的CLASSPATH等等。

ApplicationContext context =
    new ClassPathXmlApplicationContext(new String[] {"services.xml", "daos.xml"});

1.2.3 使用容器

ApplicationContext是一个维护不同beans和它们的依赖的先进工厂,使用方法:

T getBean(String name, Class<T> requiredType);

你可以取回你的beans的实例。

例如:

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

1.3 Bean概览

一个Spring IoC容器管理这一个或多个bean。这些bean通过你提供给容器的配置元数据被创建,例如在基于XML配置的<bean/>元素下定义。

在容器内部,这些bean定义通过BeanDefinition对象表示。

1.3.1 命名beans

每一个bean都有一个或者多个标识符。这些标识符在容器管理的所有bean里必须是唯一的。一个bean通常只有一个标识符,但是如果需要更多的,这个额外的标识符可以考虑别名。

你并没有被要求为一个bean提供一个名称或id。如果没有显示的提供名称或者id,容器会为这个bean生成一个唯一的名称。

Bean命名约定使用的是标准的Java实例成员变量的命名。bean的名称开头以小写字母开头,后面的字母遵循驼峰大小写形式。例如:'accountManager', 'accountService', 'userDao', 'loginController'等等。

在基于XML的配置文件里,可以使用<alias/>元素来为bean定义别名:

<alias name="fromName" alias="toName"/>

1.3.2 实例beans

一个bean定义基本上就是一个配方(recipe)用来创建一个或多个对象。当一个被命名的bean被请求时容器去查询配方,同时使用配置元数据封装的bean定义来创建(或取得)一个真是的对象。

如果你使用基于XML的配置方式,你要在<bean/>元素的class属性里具体指定要被实例的对象的类。这个class属性在一个BeanDefinition实例的内部是一个类属性。

当你通过构造器方法创建一个bean,对于所有普通的类都是适用的并且与Spring兼容。也就是说类在开发时不需要去实现任何特殊接口或者用特殊的方式编码。简单的指定bean的类就足够了。但是根据你用的IoC的类型,你可能需要一个默认的构造器。

1.4 依赖关系

一个典型的企业应用程序不是只包含一个对象(或者用Spring的说法,一个bean)。即使是最简单的应用程序也包含了几个一起工作的对象来让最终的用户看起来这是一个合乎逻辑的应用程序。下面一部分来解释你定义的许多孤立的bean是怎么变成一个对象们一起协作去到达一个目标的真正的应用程序。

1.4.1 依赖注入

Dependency injection(DI)依赖注入是一个流程由此对象定义他们的依赖,也就是说,定义与某个对象一起工作的其他对象,只有通过构造器参数、工厂方法的参数或者将属性通过set到它被构造后或从一个工厂方法返回后的对象实例 。当容器创建bean时会将这些依赖注入(injects )。相对于bean自己来控制其依赖的实例化或位置的做法,这个过程从根本上是反转的,因此叫做控制反转Inversion of Control (IoC)。

通过DI的原则代码变得更整洁,并且当对象提供了它们的依赖后解耦更有效。对象不用查找它的依赖关系也不知道这些依赖的位置或者类。正因如此你的类变得更容易测试,尤其当这些依赖是接口或者抽象基类时,允许stub或者mock的实现在单元测试中被使用。

DI存在两种主要变体,基于构造器的依赖注入和基于Setter方法的依赖注入。

基于构造器的依赖注入

基于构造器的依赖注入由容器调用一个含有一些参数的构造器来完成,每一个参数代表一个依赖。调用一个含有一些特殊参数的静态工厂方法来构造bean和基于构造器的依赖注入是基本等效的,这个论述对待一个构造器的参数和一个静态工厂方法的参数是相似的。下面的例子展示了一个类只能通过基于构造器的方式注入依赖。注意这是一个没有一点特殊的类,它是一个POJO,没有依赖容器的特殊接口,父类或者注解。

public class SimpleMovieLister {

    // SimpleMovieLister有一个依赖MovieFinder
    private MovieFinder movieFinder;

    // 一个构造器,这样Spring容器才能注入一个MovieFinder
    public SimpleMovieLister(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }

    // business logic that actually uses the injected MovieFinder is omitted...

}

构造器参数解析

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

推荐阅读更多精彩内容