Spring 3.1 中文参考文档


参考文档 3.1 (build on 20110805) 南磊 译 本文档的拷贝适用于您自己使用或是分发给他人,您不能从中收取任何费用并且任何拷贝必 须含有这个版权声明,无论是分发打印版还是电子版。 版权说明: Spring 中文版参考文档由南磊翻译,您可以自由使用或分发他人,但是您不能从中收取 任何费用,任何拷贝必须有版权声明。如有商业用途倾向,必须联系原作者和译者。 翻译文档支持网站为:http://code.google.com/p/translation (翻译期间,每周五在此更新) 译者联系方式如下,有对翻译的任何意见和建议,不要犹豫,请点击: 电子邮件:nanlei1987@gmail.com 微博:http://weibo.com/nanlei1987 第一部分 Spring framework 概述.......................................................................................................................4 第 1 章 Spring Framework 介绍.......................................................................................................................5 1.1 依赖注入和控制反转 ............................................................................................................................5 1.2 模块............................................................................................................................................................5 1.2.1 核心容器...........................................................................................................................................6 1.2.2 数据访问/整合 ................................................................................................................................6 1.2.3 Web .....................................................................................................................................................7 1.2.4 AOP 和设备组件...............................................................................................................................7 1.2.5 测试....................................................................................................................................................7 1.3 使用方案...................................................................................................................................................7 1.3.1 依赖管理和命名规约 ................................................................................................................. 11 1.3.1.1 Spring 依赖和基于 Spring ................................................................................................... 12 1.3.1.2 Maven 依赖管理 ................................................................................................................... 13 1.3.1.3 Ivy 依赖管理........................................................................................................................... 14 1.3.2 日志................................................................................................................................................. 15 1.3.2.1 不使用 Commons Logging.................................................................................................. 16 1.3.2.2 使用 SLF4J.............................................................................................................................. 16 1.3.2.3 使用 Log4J ............................................................................................................................. 18 第二部分 Spring 3 的新特性............................................................................................................................. 20 第 2 章 Spring 3.0 的新特性和增强 ............................................................................................................ 20 2.1 Java 5 ........................................................................................................................................................ 20 2.2 改进的文档 ........................................................................................................................................... 20 2.3 新的文章和教程 .................................................................................................................................. 20 2.4 新的模块组织方式和构建系统........................................................................................................ 21 2.5 新特性概述 ........................................................................................................................................... 21 2.5.1 为 Java 5 更新的核心 API........................................................................................................... 22 2.5.2 Spring 表达式语言 ........................................................................................................................ 22 2.5.3 控制反转(IoC)容器 ................................................................................................................ 23 2.5.3.1 基于 Java 的 bean 元数据.................................................................................................. 23 2.5.3.2 使用组件定义 bean 的元数据.......................................................................................... 24 2.5.4 通用的类型转换系统和字段格式化系统 .............................................................................. 24 2.5.5 数据层 ............................................................................................................................................ 24 2.5.6 Web 层............................................................................................................................................. 24 2.5.6.1 全面的 REST 支持 ................................................................................................................ 25 2.5.6.2 @MVC 的增加........................................................................................................................ 25 2.5.7 声明式的模型验证 ...................................................................................................................... 25 2.5.8 先期对 Java EE 6 的支持 ............................................................................................................. 25 2.5.9 嵌入式数据库的支持 ................................................................................................................. 25 第 3 章 Spring 3.1 的新特性和增强 ............................................................................................................ 26 3.1 新特性概述 ........................................................................................................................................... 26 第三部分 核心技术............................................................................................................................................. 27 第 4 章 IoC 容器............................................................................................................................................... 28 4.1 Spring IoC 容器和 bean 的介绍 ......................................................................................................... 28 4.2 容器概述................................................................................................................................................ 28 4.2.1 配置元数据 ................................................................................................................................... 29 4.2.2 实例化容器 ................................................................................................................................... 30 4.2.2.1 处理基于 XML 的配置元数据........................................................................................... 31 4.2.3 使用容器........................................................................................................................................ 32 4.3 Bean 概述................................................................................................................................................ 33 4.3.1 命名 bean ...................................................................................................................................... 33 4.3.1.1 在 bean 定义外面起别名................................................................................................... 34 4.3.2 实例化 bean .................................................................................................................................. 35 4.3.2.1 使用构造方法实例化 ......................................................................................................... 35 4.3.2.2 使用静态工厂方法来实例化 ............................................................................................ 35 4.3.2.3 使用实例工厂方法来实例化 ............................................................................................ 36 4.4 依赖......................................................................................................................................................... 37 4.4.1 依赖注入........................................................................................................................................ 37 4.4.1.1 基于构造方法的依赖注入 ................................................................................................ 38 4.4.1.2 基于 setter 方法的依赖注入............................................................................................. 40 4.4.1.3 解决依赖过程....................................................................................................................... 41 4.4.1.4 依赖注入示例....................................................................................................................... 42 4.4.2 深入依赖和配置 .......................................................................................................................... 44 4.4.2.1 直接值(原生类型,String,等) ............................................................................ 44 4.4.2.2 引用其它 bean(协作者) ............................................................................................... 46 4.4.2.3 内部 bean .............................................................................................................................. 47 4.4.2.4 集合......................................................................................................................................... 47 4.4.2.5 null 和空字符串..................................................................................................................... 50 第一部分 Spring framework 概述 Spring framework 是一个轻量级的解决方案,在构建一站式企业级应用程序上有很大的 潜能。Spring 是模块化的,允许你使用仅需要的部分,而不需要引入其余部分。你可以使用 IoC 容器,和 Struts 一起使用,而且你也可以仅仅使用 Hibernate 整合代码或者是 JDBC 抽象 层。Spring framework 支持声明式的事务管理,通过 RMI 或 Web Service 远程访问业务逻辑 代码,并且提供多种持久化数据的选择。它提供饿了一个全功能的 MVC 框架,允许你显式 地整合 AOP 到软件中。 Spring 被设计成非侵入式的,也就是说你的业务逻辑代码通常是不会对 Spring 框架本身 产生依赖的。在你的整合层面(比如数据访问层),一些依赖于数据访问技术和 Spring 的类 库是会存在的。但是,也很容易将这些依赖从你剩余的代码中分离出来。 本文档是 Spring 框架特性的参考指南。如果你有任何想法,建议或是对本文档的疑问, 请发送到用户邮件列表中或者是在线论坛中,论坛地址是 http://forum.springsource.org。 第 1 章 Spring Framework 介绍 Spring Framework 是一个 Java 平台,它提供了对开发 Java 应用程序的一种广泛的基础支 持。Spring 控制这个基础,那么你就可以集中精力于应用程序了。 Spring 允许你从“普通 Java 对象(POJO)”来构建应用程序,并且将应用企业级服务非 侵入地应用于 POJO 中。这个能力适用于 Java SE 编程模型,全部或部分的 Java EE。 作为应用程序的开发人员,下面就是你可以使用 Spring 平台优点的例子:  编写 Java 方法来执行数据库事务而不需要处理事务 API。  编写本地 Java 方法来访问远程程序而不需要处理远程访问 API。  编写本地 Java 方法来执行管理操作而不需要处理 JMX 的 API。  编写本地 Java 方法来处理消息而不需要处理 JMS 的 API。 1.1 依赖注入和控制反转 Java 应用程序 -- 一个宽松的术语,囊括了从被限制的 applet 到 n 层服务器端企业级应 用程序的全部 – 典型地是,包含了组成独特应用程序的合作对象。那么这些在应用程序中 的对象就会相互依赖。 尽管 Java 平台提供了丰富的应用程序开发功能,但是它也缺乏组织基本模块到一个整 体的方式,把这个任务留给了架构师和开发人员。也就是说,你可以设计如工厂,抽象工厂, 构建者,装饰者和服务定位器等模式来组合各个类和构成应用程序的对象实例。然而,这些 模式是最简单的:最佳的做法是给定一个名称,并且描述这个模式做了什么,在哪里可以应 用它,它所强调的问题是什么等等。模式使你必须自己实现的最佳实践形式化。 Spring Framework 的控制反转(Inversion of Control,IoC)组件提供组合不同的组件到完 整可用的应用程序的形式化方法来强调这个问题。Spring Framework 编写了形式化的设计模 式作为顶级对象,你可以用来整合到你的应用程序中。很多组织和研究机构使用 Spring Framework 的这个方式来设计强壮的,可维护的应用程序。 1.2 模块 Spring Framework 包含了很多特性并且组织成 20 个模块。这些模块分为核心容器,数 据访问/整合,Web,AOP(Aspect Oriented Programming,面向切面编程),设备组件和测试, 在下图中来展示。 背景 “问题是,[它们]反向控制哪一方面?”,2004 年,Martin Fowler 在他个人站点提出 了这个关于控制反转(IoC)问题。Fowler 建议重命名这个原则,使得它更好地自我解释, 同事提出了依赖注入。 要 深 入 了 解 IoC 和 DI , 可 以 参 考 Fowler 的 文 章 , 地 址 是 : http://martinfowler.com/articles/injection.html Spring 框架概要 1.2.1 核心容器 核心容器(4.1 节)包含了核心(Core), Bean 组件(Beans),上下文(Context)和表 达式语言(Expression Language)模块。 核心和 Bean(4.1 节)模块提供了框架部分内容的基础,包含 IoC 和依赖注入特性。 BeanFactory 是工厂模式的精密实现。它去掉了编程化单例的需要,并允许你解除配置和 实际程序逻辑特定依赖之间的耦合。 上下文(4.14 节)模块构建了由核心和 Bean(4.1 节)模块提供的坚实基础:它可以让 你以框架样式的风格来访问对象,这和 JNDI 注册是相似的。上下文模块集成了来自 Bean 模 块的特性并且加入了对国际化(比如使用资源束)的支持,事件传播,资源加载和 Servlet 容器显式地创建上下文。上下文模块也支持 Java EE 特性,比如 EJB,JMX 和基本的远程调用。 ApplicationContext 接口是上下文模块的焦点。 表达式语言(第 7 章)模块提供了强大的表达式语言,在运行时查询和操作对象图。这 是 JSP 2.1 规范中的统一表达式语言(unified EL)的一个扩展。该语言支持设置和获取属性 值,属性定义,方法调用,访问数组,集合和索引的上下文,逻辑和数字运算,命名变量和 从Spring 的IoC容器中以名称来获取对象。它也支持列表投影和选择,还有普通的列表聚集。 1.2.2 数据访问/整合 数据访问/整合层由 JDBC,ORM,OXM,JMS 和事务模块组成。 JDBC(13.1 节)模块提供了 JDBC 抽象层,它移除了冗长的 JDBC 编码,但解析了数据库 提供商特定的错误代码。 ORM(14.1 节)模块提供了对流行的对象-实体映射 API 的整合层,包含 JPA(14.5 节), JDO(14.4 节),Hibernate(14.3 节)和 iBatis(14.6 节)。使用 ORM 包你就可以使用全部的 O/R-映射框架并联合其它 Spring 提供的特性,比如前面提到的简单声明式的事务管理特性。 OXM(第 15 章)模块提供了支持 JAXB,Castor,XMLBeans,JiBX 和 Xstream 对对象/XML 映射实现的抽象层。 Java 消息服务(JMS(第 22 章))模块包含生成和处理消息的特性。 事务(第 11 章)模块支持对实现特定接口的类和所有 POJO(普通 Java 对象)的编程 式和声明式的事务管理。 1.2.3 Web Web 层由 Web,Web-Servlet,Web-Struts 和 Web-Portlet 模块组成。 Spring 的 Web 模块提供了基本的面向 Web 整合的特性,比如文件上传功能,IoC 容器 的初始化使用了Servlet 的监听器和变相Web的应用上下文。它还包含了和 Web相关的 Spring 的远程调用支持部分。 Web-Servlet 模块包含了 Spring 对 Web 应用的模型-视图-控制器(MVC(16.1 节))实现。 Spring 的 MVC 框架提供了一个在领域模型代码和 Web 表单之间的整洁分离,并且整合了其 它所有 Spring 框架的特性。 Web-Struts 模块包含了使用 Spring 应用程序整合经典 Strtus Web 层的支持类。要注意这 个支持从 Spring 3.0 开始就废弃了。可以考虑迁移应用程序到 Struts 2.0 和 Spring 的整合或者 到 SpringMVC 方案。 Web-Portlet 模块提供用于 portlet 环境和 Web-Servlet 模块功能镜像的 MVC 实现。 1.2.4 AOP 和设备组件 Spring 的 AOP(8.1 节)模块提供了 AOP 联盟-允许的的面向切面编程实现,允许你定义 如方法-拦截器和横切点来整洁地解耦应该被分离的功能实现代码。使用源码级的元数据功 能,也可以混合行文信息到代码中,这个方式和.NET 属性很相似。 分离的 Aspects 模块提供对 AspectJ 的整合。 设备组件模块提供了设备对类的支持还有类加载器的实现来用于特定的应用服务器。 1.2.5 测试 测试模块支持 Spring 组件和 Junit 或 TestNG 的测试。它提供了 Spring 应用上下文的一致 加载并缓存这些上下文内容。它也提供 mock 对象,你可以用来孤立地测试代码。 1.3 使用方案 前面描述的构建块使得 Spring 可以在很多方案中作为业务逻辑实现的选择,从 applet 到使用了 Spring 的事务管理功能和 Web 框架整合的功能完善的企业级应用。 典型地功能完善的 Spring Web 应用 Spring 的声明式事务管理特性(11.5 节)使得 Web 应用程序可以全部事务化,就好像 使用了 EJB 容器管理的事务。全部的自定义业务逻辑可以使用简单的 POJO 来实现并且被 Spring 的 IoC 容器来管理。额外的服务包含对发送邮件的支持,验证对 Web 层独立,这可以 让你选择在哪里执行验证规则。Spring 的 ORM 支持对 JPA,Hibernate,JDO 和 iBatis 进行了整 合;比如,当使用 Hibernate 时,你可以继续使用已有的映射文件和标准的 Hibernate 的 SessionFactory 配置。表单控制器无缝地整合了 Web 层 和 领 域 模 型 , 移 除 了 ActionForm 或其它为领域模型转换 HTTP 参数的类需要。 使用了第三方 Web 框架的 Spring 中间层 有时,环境并不允许你完全转换到一个不同的框架。Spring Framework 不强制你使用它 其中部分;它并不是一个所有或没有的方案。已有的使用 WebWork,Struts,Tapestry 或其 它 UI 框架构建的前端可以使用基于 Spring 的中间层来整合,这就允许你使用 Spring 的事务 特性。你仅仅需要给你的业务逻辑装上 ApplicationContext,对整合 Web 层使用 WebApplicationContext。 远程调用使用方案 当你需要通过 Web Service 访问已有的代码,你可以使用 Spring 的 Hessian-,Burlap-, Rmi-或 JaxPpcProxyFactory 类。开启远程访问已有的应用并不困难。 EJB – 包装已有的 POJO Spring Framework 也提供了对企业级 Java Bean 的访问和抽象层(第 21 章),这就可以 重用已有的 POJO,可扩展包装它们到无状态会话 bean,不安全的 Web 应用可能需要声明式 安全。 1.3.1 依赖管理和命名规约 依赖管理和依赖注入是不同的概念。要在应用程序中添加 Spring 优美的特性(比如依 赖注入),你需要组合所需的类库(jar 文件)并添加到在运行时环境的类路径中,而编译时 也是需要的。这些依赖不是注入的虚拟组件,而是文件系统(通常是这样)的物理资源。依 赖管理的过程包括定位那些资源,存储它们并将它们添加到类路径中。依赖可以是直接的(比 如,应用程序在运行时需要 Spring),或者是间接的(比如,应用程序需要的 commons-dbcp 还依赖 commons-pool)。间接的依赖也被认为是“过度的”,而且那些依赖本身就难以识 别和管理。 如果你决定使用 Spring,那么你需要获得 jar 包的拷贝,包括你所需要的 Spring 的模块。 为了使用上的便捷,Spring 被打包成模块集合,尽可能地分离了其中的依赖,那么比如如果 你不想编写 Web 应用程序,就不需要 spring-web 模块。要参考 Spring 模块的库,本指南使 用了一个速记命名规约 spring-*或者 spring-*.jar,这里的“*”代表了模块的短名 称(比如,spring-core,spring-webmvc,spring-jms 等)。真实的 jar 文件命名或 许就是这种形式的(看下面的示例),但也有可能不是,通常它的文件名中还有一个版本号 (比如,spring-core-3.0.0.RELEASE.jar)。 通常,Spring 在四个不同的地方发布组件:  在社区下载点 http://www.springsource.org/downloads/community。这里你可以找到所有 Spring 的 jar 包,它们被压缩到一个 zip 文件中,可以自由下载。这里 jar 包的命名从 3.0 版本开始以 org.springframework.*-.jar 格式。  Maven 的中央库,也是 Maven 检索的默认资源库,并不会检索特殊的配置来使用。很 多 Spring 依赖的常用类库也可以从 Maven 的中央库中获得,同事 Spring 社区绝大多数 用户使用 Maven 作为依赖管理工具,这对于他们来说是很方便的。这里 jar 包的命名是 spring-*-.jar 格 式 的 , 并 且 Maven 的 groupId 是 org.springframework。  企业级资源库(Enterprise Bundle Repository,EBR),这是由 SpringSource 组织运营的, 同时也提供和 Spring 整合的所有类库。对于所有 Spring 的 jar 包及其依赖,这里也有 Maven 和 Ivy 的资源库,同时还有很多开发人员在使用 Spring 编写应用程序时能用到的 大量常用类库。而且发布版本,里程碑版本和开发版本也都在这里部署着。这里 jar 文 件的命名和社区下载的(org.springframework.*-.jar)一致,并且 依赖的外部类库(不是来自 SpringSource 的)也是使用的这种“长的”形式,并以 com.springsource 作为前缀。可以参考 FAQ 部分获取更多信息。  在 Amazon S3 为开发和里程碑发布(最终发布的拷贝这里也会有)设置的公共 Maven 资源库中。Jar 文件名称和 Maven 中央库是一样的,那么这里是获取 Spring 开发版本来 使用的地方,其它的类库是部署于 Maven 中央库的。 那么首先你要决定的事情是如何管理你的依赖:很多人使用自动化的系统,比如 Maven 和 Ivy,但是你也可以手动下载所有的 jar 文件。当使用 Maven 或 Ivy 获取 Spring 时,之后你 需要决定你要从哪里来获取。通常来说,如果你关注 OSGi,那就使用 EBR,因为它对所有 的 Spring 依赖兼容 OSGi,比如 Hibernate 和 Freemarker。如果对 OSGi 不感兴趣,那么使用 哪个都可以,他们也各有利弊。通常讲,为你的项目选择一个或者另外一个;但是不要混用。 因为相对于 Maven 中央库而言,EBR 组件非常需要一个不同的命名规则,那么这就特别重 要了。 表 1.1 Maven 中央库和 SpringSource EBR 资源库的比较 特性 Maven 中央库 EBR OSGi 的兼容 不明确 是 组件数量 成千上万;所有种类 几百个;是 Spring 整合用到的 一致的命名规约 没有 有 命名规约:GroupId 相异。新组件通常使用域 名,比如 org.slf4j。老组件 通常仅仅使用组件名,比 如 log4j。 原始的域名或主包根路径,比如 org.springframework 命名规约:ArtifactId 相异。通常是项目或模块 名,使用连字符“-”分隔, 比如 spring-core,log4j。 捆绑符号名称,从主包路径分离,比如 org.springframework.beans。如果 jar 需要 修补以保证兼容 OSGi,那么就附加 com.springsource ,比如 com.springsource.org.apache.log4j 命名规约:Version 相异。很多新的组件使用 m.m.m 或 m.m.m.X(m 是 数字,X 是文本)。老的使 用 m.m。有一些也不是。 顺序是确定的但通常并不 可靠,所以不是严格的可 靠。 OSGi 版本数字 m.m.m.X,比如 3.0.0.RC3。 文本标识符使用相同的数字值规定版本 的字母顺序。 发布 通常是自动通过 rsync 或 源码控制更新。项目作者 可以上传独立的 jar 文件 到 JIRA。 手动(由 SpringSource 控制的 JIRA) 质量保证 根据政策。精确度是作者 的责任。 宽泛的 OSGi 清单,Maven POM 和 Ivy 元 数据。QA 由 Spring 团队执行。 主办 Contegix 提供。由 Sonatype 和一些镜像构成。 由 SpringSource 的 S3 构成 搜索工具 很多 http://www.springsource.com/repository 和 SpringSource 工具 整合 通过和 Maven 依赖管理的 STS 来整合 通过 Maven,Roo,CloudFoundry 的 STS 进行广泛整合 1.3.1.1 Spring 依赖和基于 Spring 尽管 Spring 提供整合和对大量企业级及其外部工具的支持,那么它也有心保持它的强 制依赖到一个绝对小的数目:你不需要为了简单的使用去定位并下载(甚至是自动地)大量 的 jar 文件来使用 Spring。对于基本的依赖注入那只需要一个强制的外部依赖,就是日志(可 以参考下面关于日志的深入介绍)。 下面,我们来概述一下配置一个基于 Spring 的应用程序所需的配置,首先使用 Maven 和 Ivy。在所有的示例中,如果有那一点不清楚,可以参考你所使用的依赖管理系统的文档, 或者参考一些示例代码 – Spring 本身在构建时使用 Ivy 来管理依赖,而我们大多数的示例使 用 Maven。 1.3.1.2 Maven 依赖管理 如果你正在使用 Maven 来进行依赖管理,那么你就不需要明确地提供日志依赖。比如, 要为应用程序配置创建应用上下文并使用依赖注入,你的 Maven 依赖可以是这样的: 就是这么简单。要注意如果你在编译代码时不需要 Spring 的 API,那么 scope 可以声明 为 runtime,这就可以用于典型的基本依赖注入用例。 在上面的示例中,我们使用了 Maven 中央库的命名规约,那么就可以在 Maven 中央库 或 SpringSource S3 的 Maven 资源库起作用。要使用 S3 的 Maven 资源库(比如里程碑版本或 开发快照),你需要在 Maven 的配置文件中指定资源库的位置。对于完整发布版如下: 对于里程碑版本如下: 对于开发快照版本如下: org.springframework spring-context 3.0.0.RELEASE runtime com.springsource.repository.maven.release http://maven.springframework.org/release/ false com.springsource.repository.maven.milestone http://maven.springframework.org/milestone/ false com.springsource.repository.maven.snapshot http://maven.springframework.org/snapshot/ true 要使用 SrpingSource 的 EBR,那么你还需要一个对依赖不同的命名规约。名称通常很容 易去猜测,比如这个示例中,就是: 你也可能需要明确地声明资源库的位置(仅仅 URL 是重要的): 如果你手动去管理依赖,这个在上面声明的资源库 URL 是不可以浏览的,但是也有一 个用户界面,地址是 http://www.springsource.com/repository,这可以用来搜索和下载依赖。 它也有Maven和Ivy配置的代码片段,你可以复制下来并粘贴到你所使用的工具中,很方便。 1.3.1.3 Ivy 依赖管理 如果你使用 Ivy 来管理依赖,那么有一些简单的命名和配置选项。 要配置 Ivy 定位到 SpringSource EBR,需要添加如下 resolvers 到你的 ivysettings.xml 中: org.springframework org.springframework.context 3.0.0.RELEASE runtime com.springsource.repository.bundles.release http://repository.springsource.com/maven/bundles/releas e/ 上面的 XML 并不是合法的,因为行太长了 – 如果你要复制粘贴,那么要移除中部 url 模式部分结尾额外的行。(中文文档中已经去除) 一旦 Ivy 配置好去查看 EBR,那么添加依赖就很简单了。只要拉起在资源库浏览器中的 捆绑详细信息页面,你就会发现为你准备好的 Ivy 代码片段,你就可以将它包含到你的依赖 部分中了。比如(在 ivy.xml 中): 1.3.2 日志 对于 Spring 来说,日志是一个非常重要的依赖,因为 a)这是唯一的强制外部依赖,b) 开发人员都会想看到他们实用工具的一些输出内容,而且 c)Spring 整合了多种工具,它们都 会选择一种日志依赖。应用程序开发人员的目标之一就是在核心位置对整个应用程序有一个 统一的日志配置,包含对全部的外部组件。因为日志框架有很多种选择,那么这就可能有些 难以选择了。 Spring 中强制的日志依赖是 Jakarta 的 Commons Logging API(JCL)。我们的编译是基于 JCL 的,而且我们使扩展 Spring Framework 的类对 JCL 的 Log 对象都是可见的。对于用户来 说,所有 Spring 的版本都使用相同的日志包是很重要的:因为向后兼容特性的保留,迁移 是很容易的,扩展 Spring 的应用程序也是这样。我们这样做就是使 Spring 中的模块明确地 基于 commons-logging(JCL 的典型实现),在编译时也使得其它模块都基于它。如果你 在使用 Maven,并想知道在哪儿获取到的 commons-logging 依赖,那就是从 Spring 中被 称作是 spring-core 的核心模块中获取的。 关于 commons-logging 比较好的是你不需要做其它的步骤就可以使应用程序工作。 它有一个运行时的发现算法,在我们都知道的类路径下寻找其它日志框架,并且使用它认为 是比较合适的(或者告诉它你需要使用的是哪一个)一个。如果没有可用的,那么你会得到 一个来自 JDK(java.util.logging 或者简称为 JUL)看起来还不错的日志。那么你会发现很多时 候,Spring 应用程序工作中会有日志打印到控制台上,这是很重要的。 1.3.2.1 不使用 Commons Logging 不幸的是,commons-logging 的运行时发现算法对最终用户方便是有问题的。如果 我们可以让时光倒流并让 Spring 从现在开始作为一个新的项目,那么我们会使用不同的日 志依赖。那么首选的可能是 Java 简单的日志门面(SLF4J),它也被 Spring 的开发人员在它们 的应用程序中很多其它的工具所使用。 关闭 commons-logging 也简单:仅仅要确认在运行时不在类路径下就可以了。在 Maven 中去掉这个依赖,因为 Spring 依赖声明的时候会带进来,那么就需要这么来做一下。 目前这个应用程序可能就不能用了,因为在类路径中没有 JCL API 的实现了,所以要修 复这个问题就要提供另外一种实现了。在下一节中,我们来展示如何提供一个可选的 JCL 的 实现,我们使用 SLF4J 作为示例。 1.3.2.2 使用 SLF4J SLF4J 是一个干净的依赖,在运行时也比 commons-logging 效率更高,因为它使用了 编译时构建而不是运行时去发现其它整合的日志框架。这也就意味着你可以更明确地在运行 时去做什么,并且去声明或配置。SLF4J 为很多通用的日志框架提供的绑定,所以通常你可 以选择已有的一个,并绑定配置或管理。 SLF4J 为很多通用日志框架提供绑定,包括 JCL,并且也可以反向:桥接其它日志框架和 它本身。所以在 Spring 中使用 SLF4J 那么就需要使用 SLF4J-JCL 桥来代替 commons-logging 依赖。只要配置好了,那么来自 Spring 的日志调用就会被翻译成调用 SLF4J 的 API,如果在 你应用程序的其它类库使用那个 API,那么你会有一个单独的地方来配置和管理日志。 一个常用的选择是桥接 Spring 到 SLF4J,之后提供从 SLF4J 到 Log4J 的明确绑定。你需要 提供 4 种依赖(并排除已经存在的 commons-logging):桥接工具,SLF4J API,绑定到 Log4J 的工具,还有 Log4J 本身的实现。那么在 Maven 中,你就可以这样来做: org.springframework spring-context 3.0.0.RELEASE runtime commons-logging commons-logging 这看起来就好像很多依赖都需要日志。确实是这样,但它是可选的,而且它的性能要比 由于类加载器问题的 commons-logging 好很多,尤其是如果你使用了一个严格限制的容 器,比如 OSGi 平台。据称那也有性能优势,因为绑定是编译时的而不是运行时的。 另外,在 SLF4J 用户中一个较为常见的选择是使用很少步骤并产生更少的依赖,就是直 接绑定到 Logback。这会移除额外的绑定步骤,因为 Logback 直接实现了 SLF4J,所以你仅仅 org.springframework spring-context 3.0.0.RELEASE runtime commons-logging commons-logging org.slf4j jcl-over-slf4j 1.5.8 runtime org.slf4j slf4j-api 1.5.8 runtime org.slf4j slf4j-log4j12 1.5.8 runtime log4j log4j 1.2.14 runtime 需要依赖两个类库而不是四个(jcl-over-slf4j 和 logback)。 如果你那么做了,你可 能还需要从其它外部依赖(而不是 Spring)中去除 slf4j-api 的依赖,因为你仅仅想在类路径 中有 API 的一个版本。 1.3.2.3 使用 Log4J 很多人出于配置和管理目的而使用 Log4j 作为日志框架。这也很有效率并且易于创建, 而且事实上它也是我们构建和测试 Spring 时,在运行时环境中使用的。Spring 也提供一些工 具来配置和初始化 Log4j,所以在某些模块中它也提供了可选的编译时对 Log4j 的依赖。 要让 Log4j 和默认的 JCL 依赖(commons-logging)起作用,你所要做的就是将 Log4j 放置到类路径下,并且提供配置文件(在类路径的根路径下放置 log4j.properties 或 log4j.xml)。而对于 Maven 用户来说,下面可以是依赖的声明: 下面是 log4j.properties 打印到控制台的日志的配置示例: 运行时容器和本地的 JCL 很多用户在容器中运行Spring 应用程序,而容器本身提供了 JCL 的实现。IBM Webshphere 应用服务器(WAS)就是这种类型。这通常会引起问题,而不幸的是没有解决的银弹;很多 情况下仅仅从应用程序中去除 commons-logging 是不够的。 要清楚地认识这一点:这个问题通常和 JCL 本身一同报告,或者是和 commons-logging:而不是绑定 commons-logging 到另外的框架(通常是 Log4J)。这 org.springframework spring-context 3.0.0.RELEASE runtime log4j log4j 1.2.14 runtime log4j.rootCategory=INFO, stdout log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %t %c{2}:%L - %m%n log4j.category.org.springframework.beans.factory=DEBUG 可能会引发问题,因为 commons-logging 改变了它们在运行时环境里,在一些容器中发 现老版本(1.0)而很多人现在使用新的版本(1.1)。 Spring 不会使用任何不通用的 JCL API 部分,所以这里不会有问题,但是 Spring 或你的应用程序尝试去进行日志记录,你可以发 现绑定到 Log4J 是不起作用的。 这种在 WAS 上的情况,最简单的做法就是颠倒类加载器的层次(IBM 称之为“parent last”),那么就是应用程序控制而不是容器来控制 JCL 依赖。这种选择并不总是开放的,但 是在公共领域的代替方法也有其它的建议,根据确切的版本和容器的特性集,您所要求的效 果可能会不同。 第二部分 Spring 3 的新特性 第 2 章 Spring 3.0 的新特性和增强 如果你使用 Spring Framework,你会看到 Spring 现在有两个主要的修订版本:在 2006 年 12 月发布的 Spring 2.0,在 2007 年 11 月发布的 Spring 2.5。现在就是第三个版本 Spring 3.0 了。 2.1 Java 5 框架的整体代码都已经修订来支持 Java 5 的新特性,比如泛型,可变参数和其它的语言 改进。我们也尽最大努力来保持代码的向后兼容。现在我们也有一致的泛型集合和 Map 使 用,泛型 FactoryBean 的一致使用,还有在 Spring AOP API 中对桥接方法的一致解决方案。 泛型上下文监听器仅仅自动接收特定的事件类型。所有的如 TransactionCallback 和 HibernateCallback 回调接口现在也都声明为泛型返回值。总之,Spring 核心代码库都已经为 Java 5 而修订和优化。 Spring 的TaskExecutor 抽象也已经为和Java 5的java.util.concurrent 的紧密整合而更新了。 我们现在为可调用和特性提供顶级的类的支持,还有 ExecutorService 适配器,ThreadFactory 整合等。这和 JSR-236(Java EE6 的并发工具)尽可能是一样的。此外,我们提供对使用新 的@Async 注解(或者 EJB 3.1 的@Asynchronous 注解)异步方法调用的支持。 2.2 改进的文档 Spring 参考文档也有很大的更新,并反射出 Spring 3.0 的改进和新特性。而每一项努力 都是来保证在文档中没有错误,一些错误还会多多少少的存在。如果你确实发现了任何的错 字或者是严重的错误,你可以在午餐期间将它们画上圈,然后请将这些错误报告给 Spring 团队,你可以打开一个问题。 2.3 新的文章和教程 有很多优秀的文章和教程来展示如何开始使用 Spring 3 新特性。请在 Spring 文档页面来 阅读它们。 示例也已经更新采用了 Spring 3 的新特性。此外,示例也已经从源码树中移入到专用的 SVN 资 源 库 中 了 。 访问的地 址 是 : https://anonsvn.springframework.org/svn/spring-samples/。 因此,这些示例不会跟在 Spring 3 的发布包中了,需要从上面提到的资源库中分别来下 Java SE 和 Java EE 支持 Spring Framework 现在完全基于 Java 5 和 Java 6。 此外,Spring 还兼容 J2EE 1.4 和 Java EE5,同时也会介绍一些对 Java EE6 的先期支持。 载。而本文档会继续引用一些示例(特别是 Petclinic)来陈述各种特性。 注意 要获取关于 Subversion(或简称 SVN)的更多信息,可以参考项目主页,地址是: http://subversion.apache.org/。 2.4 新的模块组织方式和构建系统 框架的模块已经被修订了,现在分别组织成一个源码分支是一个 jar 文件:  org.springframework.aop  org.springframework.beans  org.springframework.context  org.springframework.context.support  org.springframework.expression  org.springframework.instrument  org.springframework.jdbc  org.springframework.jms  org.springframework.orm  org.springframework.oxm  org.springframework.test  org.springframework.transaction  org.springframework.web  org.springframework.web.portlet  org.springframework.web.servlet  org.springframework.web.struts 现在我们使用新的 Spring 构建系统,从熟知的 Spring Web Flow 2.0 中而来,它给力我们 如下特性:  基于 Ivy 的“Spring 构建”系统  一致的开发过程  一致的依赖管理  一致的 OSGIi 清单的生成 2.5 新特性概述 下面的列表是 Spring 3.0 的新特性,我们在后面章节的详细讲述会覆盖这些特性。  Spring 表达式语言  IoC 增加/基于 Java 的 bean 元数据  通用的类型转换系统和字段格式化系统  对象转 XML 映射功能(OXM)从 Spring Web Service 项目中移出  全面的 REST 支持  @MVC 的增加 注意: Spring.jar 文件包含了几乎所有框架内容,现在不再提供了。  声明式的模型验证  先期对 Java EE 6 的支持  嵌入式数据库的支持 2.5.1 为 Java 5 更新的核心 API BeanFactory 接口尽可能返回该类型 bean 的实例:  T getBean(Class requiredType)  T getBean(String name, Class requiredType)  Map getBeansOfType(Class type) Spring 的 TaskExecutor 接口现在扩展了 java.util.concurrent.Executor:  扩展的 AsyncTaskExecutor 支持标准的可调用特性 新的基于 Java 5 的转换 API 和 SPI:  无状态的 ConversionService 和转换器  取代标准 JDK 的 PropertyEditors 泛型化的 ApplicationListener 2.5.2 Spring 表达式语言 Spring 引入了一种表达式语言,这和统一 EL 在语法上很相似,但是提供了很多特性。 这种表达式语言可以用于定义基于 XML 和注解的 bean,也可以作为表达式语言的基础,支 持贯穿整个Spring 框架的组合。这些新功能的详细内容可以在第 7章 Spring 表达式语言(SpEL) 中查看。 Spring 表达式语言被用来为 Spring 社区提供一个单一的,支持良好的表达式语言,可以 被用于 Spring 系列的所有产品。它的语言特性由 Spring 系列产品的所有项目的需求来驱动, 包括基于 Eclipse 的 SpringSource Tool Suite(SpringSource 组织开发的工具套件,译者注)代 码完成支持工具的需求。 下面是表达式媛媛如何被用于配置数据库属性设置的示例: 如果你使用注解来配置组件,那么功能也是可用的: @Repository public class RewardsTestDatabase { @Value("#{systemProperties.databaseName}") public void setDatabaseName(String dbName) { … } @Value("#{strategyBean.databaseKeyGenerator}") public void setKeyGenerator(KeyGenerator kg) { … } } 2.5.3 控制反转(IoC)容器 2.5.3.1 基于 Java 的 bean 元数据 从 Java Config 项目中来的一些核心特性现在也被加入到 Spring Framework 中了。这就是 说下面的注解是直接支持的。  @Configuration  @Bean  @DependsOn  @Primary  @Lazy  @Import  @ImportResource  @Value 下面是一个 Java 类提供基本配置信息的示例,使用了新的 Java Config 特性: package org.example.config; @Configuration public class AppConfig { private @Value("#{jdbcProperties.url}") String jdbcUrl; private @Value("#{jdbcProperties.username}") String username; private @Value("#{jdbcProperties.password}") String password; @Bean public FooService fooService() { return new FooServiceImpl(fooRepository()); } @Bean public FooRepository fooRepository() { return new HibernateFooRepository(sessionFactory()); } @Bean public SessionFactory sessionFactory() { // 装配一个session factory AnnotationSessionFactoryBean asFactoryBean = new AnnotationSessionFactoryBean(); asFactoryBean.setDataSource(dataSource()); // 其它配置 return asFactoryBean.getObject(); } @Bean public DataSource dataSource() { return new DriverManagerDataSource(jdbcUrl, username, password); } } 要让它发挥作用,你需要在应用上下文 XML 文件中添加如下的组件扫描项。 或 者 你 可 以 直 接 使 用 AnnotationConfigApplicationContext 来 启 动 被 @Configuration 注解的类: 参考 4.12.2 节“使用 AnnotationConfigApplicationContext 实例化 Spring 容器”来获取关 于 AnnotationConfigApplicationContext 的全部信息。 2.5.3.2 使用组件定义 bean 的元数据 @Bean 注解的方法也可以支持内部的 Spring 组件。它们贡献工厂 bean 的定义到容器中。 参考 4.10.4 节“使用组件定义 bean 的元数据”来获取更多信息。 2.5.4 通用的类型转换系统和字段格式化系统 通用的类型转换系统(参考 6.5 节)已经引入了。系统现在被 SpEL 使用来进行类型转 换,当绑定 bean 的属性值时也会被 Spring 容器和数据绑定器使用。 此外,格式化(参考 6.6 节)SPI 也被引入了,来格式化字段值。这个 SPI 对 JavaBean 的 PropertyEditors 提供了简单的,更强壮替代,在如 Spring MVC 的客户端环境中来使用。 2.5.5 数据层 现在,对象到 XML 映射功能(OXM)被从 Spring Web Service 项目中移到 Spring Framework 的核心中。这个功能可以在 org.springframework.oxm 包下找到。关于使用 OXM 模块 的更多信息可以在第 15 章使用 O/X 映射器编组 XML 找到。 2.5.6 Web 层 对于 Web 层来说,最令人兴奋的新特性是对构建 RESTful Web Service 和 Web 应用程序 的支持。也有一些新的注解可以用于任意的 Web 应用程序。 public static void main(String[] args) { ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class); FooService fooService = ctx.getBean(FooService.class); fooService.doStuff(); } 2.5.6.1 全面的 REST 支持 对构建RESTful应用程序服务器端的支持已经作为已有的注解驱动的MVC web框架而提 供了。客户端的支持由 RestTemplate 类来提供,和其它的模板类是相似的,比如 JdbcTemplate 和 JmsTemplate。服务器和客户端两者的 REST 功能都使用 HttpConverter 来在对象和它们在 HTTP 请求和响应代表之间方便的转换。 MarshallingHttpMessageConverter 使用之前提到的对象到 XML 映射功能。 可以参考 MVC(第 16 章)和 RestTemplate(20.9.1 节)部分获取更多信息。 2.5.6.2 @MVC 的增加 mvc 命名空间被引入来大大简化 Spring MVC 的配置。 其它如@CookieValue 和 @RequestHeader 的注解也被加入了。参考使用 @CookieVlue 注解映射 cookie 值(16.3.3.9 节)和使用@RequestHeader 注解映射请求头部属 性(16.3.3.10 节)来获取更多信息。 2.5.7 声明式的模型验证 一些验证增强(6.7 节),包括 JSR303 支持,使用 Hibernate 校验器作为默认提供者。 2.5.8 先期对 Java EE 6 的支持 通过使用新的@Async 注解(或 EJB 3.1 的@Asynchronous 注解)我们提供异步方法调用。 JSR 303,JSF 2.0,JPA 2.0 等 2.5.9 嵌入式数据库的支持 现在也提供了对嵌入式 Java 数据库引擎(13.8 节)的方便支持,包括 HSQL,H2 和 Derby。 第 3 章 Spring 3.1 的新特性和增强 在 Spring 3.0 引入的支持之上构建,Spring 3.1 现在还在开发中,目前 Spring 3.1 M2 才刚 刚发布。 3.1 新特性概述 (该部分内容待 Spring 3.1 GA 发布后翻译) 第三部分 核心技术 参考文档的这一部分涵盖了 Spring Framework 中不可或缺的技术。 这些内容最主要的是 Spring Framework 的控制反转(IoC)容器。Spring Framework 的 IoC 容器的完全使用是紧跟其后的 Spring 的面向切面编程(AOP)技术的完全覆盖。Spring Framework 有它自己的 AOP 框架,在概念上很容易去理解,在 Java 企业级编程中,它成功 地解决了 80%的 AOP 需求的功能点。 也提供了涵盖的 Spring 和 AspectJ(目前最丰富的 - 在功能方面 – 当然是在 Java 企业 级空间中最成熟的 AOP 实现)的整合。 最终,通过测试驱动开发(test-driven-development,TDD)的软件开发方法,也是 Spring 团队所主张的,所以 Spring 对整合测试的支持也涵盖到了(沿袭单元测试的最佳实践)。Spring 团队也发现了 IoC 的正确使用,当然,这会让单元和集成测试更容易(setter 方法的存在和 类的适当的构造方法可以使得它们很容易的在测试时连接在一起,而不需要设立服务定位器 注册和诸如此类的方法)。这章专门的测试又往说服你。  第 4 章,IoC 容器  第 5 章,资源  第 6 章,验证,数据绑定和类型转换  第 7 章,Spring 表达式语言(SpEL)  第 8 章,使用 Spring 进行面向切面编程  第 9 章,Spring 的 AOP API  第 10 章,测试 第 4 章 IoC 容器 4.1 Spring IoC 容器和 bean 的介绍 本章涵盖了 Spring Framework 的控制反转容器(IoC)[参考 1.1 节的背景]原则的实现。 IoC 也被称为是依赖注入(DI)。这是一个对象定义它们依赖的过程,也就是说,它们使用的 其它对象,仅仅通过构造方法参数,工厂方法参数或在对象被创建后的实例上设置的属性, 亦或者是从工厂方法返回的参数。之后容器在它创建 bean 的时候注入那些依赖。这个过程 是根本上的反向,因此名称是控制反转(IoC), bean 本身控制实例化或直接地使用类的构 造来定位它的依赖,或者是如服务定位器模式的机制。 org.springframework.beans 和 org.springframework.context 包是 Spring Framework 的 IoC 容器的基础。BeanFactory 接口提供高级的配置机制,可以管理任意类 型的对象。ApplicationContext 是 BeanFactory 的子接口。它添加了和 Spring 的 AOP 特性很简便的整合;消息资源处理(用于国际化 i18n),事件发布;应用层特定的上下文, 比如用于 Web 应用程序的 WebApplicationContext。 总之,BeanFactory 提供了配置框架和基本功能,而 ApplicationContext 添加 了更多企业级开发特定的功能。ApplicationContext 是 BeanFactory 完整的超集, 专门用于本章,来描述 Spring 的 IoC 容器。对于使用 BeanFactory 而不是 ApplicationContext 的更多信息,可以参考 4.15 节“BeanFactory”。 在 Spring 中,对象构成应用程序的骨感,它们是由 Spring 的 IoC 容器管理的,并被称为 bean。一个 bean 就是一个实例化并组装的对象,由 Spring 的 IoC 容器来管理。否则,bean 就是应用程序中众多对象之一。Bean 和它们之间的依赖,反射出由容器使用的配置元数据。 4.2 容器概述 org.springframework.context.ApplicationContext 接口代表了 Spring 的 IoC 容器,负责实例化,配置和装配上述的 bean。容器获得指示来实例化某对象,配置并装 配,这都是通过读取配置元数据实现的。配置元数据在 XML 中,Java 注解或 Java 代码中来 表示。它允许你表达编写应用程序的对象,还有对象间丰富的相互依存的关系。 ApplicationContext 接口的一些实现使用 Spring 开箱的支持。在独立的应用程序 中,通常是来创建 ClassPathXmlApplicationContext 或 FileSystemXmlApplicationContext 的实例。XML 是定义配置元数据的传统格式,你 可以指示容器使用 Java 的注解或是代码作为元数据的格式,提供少量的 XML 配置声明来开 启对这些额外的元数据格式的支持。 在很多应用场景中,明确的用户代码不需要实例化一个或者多个 Spring IoC 容器的实例。 比如,在 Web 应用场景中,在应用程序的 web.xml 中简单的八(左右)行样板 J2EE 描述 符 XML 文件通常就够了(参考 4.14.4 节“对 Web 应用程序方便的应用上下文实例化”)。如 果你正使用 SpringSource 的工具套件,Eclipse 支持的开发环境或者是 Spring ROO 这样的样板 配置,就可以容易地被创建,点几下鼠标或按键就可以了。 下图是 Spring 如何工作的高级别视图。你的应用程序类联合配置元数据,所以在 ApplicationContext 被创建和实例化后,就得到了一个完全配置的可执行系统或程序。 Spring 的 IoC 容器 4.2.1 配置元数据 正如上图所示,Spring 的 IoC 容器处理配置元数据的一种形式;这个配置元数据代表了 你作为应用开发人员是如何告诉 Spring 容器在你的应用程序中来实例化,配置并装配对象 的。 配置元数据传统上是以直观的 XML 格式提供的,这是本章的大部分内容使用它来传达 Spring IoC 容器关键概念和功能。 注意 基于 XML 的元数据并不是唯一的配置元数据格式。这种配置元数据真正写入时,Spring 的 IoC 容器本身和这种格式完全脱钩。 关于 Spring 容器使用元数据格式的信息,可以参考:  基于注解的配置(4.9 节):Spring 2.5 引入了对基于注解元数据的支持。  基于 Java 的配置(4.12 节):从 Spring 3.0 开始,很多由 Spring JavaConfig 项目提供的特 性称为 Spring Framework 的核心。因此你可以在应用程序外部来定义 bean,使用 Java 代码而不是 XML 文件。要使用这些新的特性,请参考@Configuration,@Bean, @Import 和@DependsOn 注解 Spring 配置典型的是最少由一个容器必须管理的 bean 定义构成。基于 XML 的配置元数 据展示了这些 bean 的配置是用在顶级元素中的元素完成的。 这些 bean 的定义对应构成应用程序中真实的对象。比如你定义的服务层的对象,数据 访问对象(Data Access Object,DAO),表示对象比如 Struts 的 Action 实例,基础设置对象 比如 Hibernate 的 SesstionFactories,JMS 的 Queues 等这些典型的例子。而不用在容 器中定义细粒度的领域模型对象,因为这通常是由 DAO 和业务逻辑负责创建并加载的领域 对象。但是你也可以使用 Spring 和 AspectJ 整合来配置创建在 IoC 容器控制之外的对象。参 考使用在 Spring 中使用 AspectJ 来对领域对象进行依赖注入(8.8.1 节)。 下面的示例展示了基本的基于 XML 的配置元数据的结构: id 属性是一个字符串,用来标识定义的独立的 bean。class 属性定义了 bean 的类型, 需要使用类的完全限定名。id 属性的值指的就是协作对象。指写作对象的 XML 在这个示例 中没有展示;参考依赖(4.4 节)来获取更多信息。 4.2.2 实例化容器 实例化 Spring 的 IoC 容器是很简单的。定位路径或所有路径提供给 ApplicationContext 的构造方法,实际上是表示资源的字符串,它就允许容器从各种外 部资源比如本地文件系统,Java 的 CLASSPATH 等来加载配置元数据 注意 在学习过 Spring 的 IoC 容器之后,你可能想更多了解 Spring 的 Resource 抽象,这在 第 5 章,资源中会描述,它提供了一个从定义 URI 语法的位置读取输入流的简便机制。特别 是,Resource 路径用来构建应用程序上下文,这会在 5.7 节“应用上下文和资源路径”中 来描述。 下面的示例展示了服务层代码(services.xml)的配置文件: ApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"services.xml", "daos.xml"}); 下面的示例展示了数据访问对象的 daos.xml 文件: 在上面的示例中,服务层代码由类 PetStoreServiceImpl 和两个基于 iBatis(iBatis 现已更名为 MyBatis,译者注)对象/实体映射框架的数据访问对象 SqlMapAccountDao 和 SqlMapItemDao 构成。property 的 name 元素指的是 JavaBean 的属性名,而 ref 元 素指的是其它 bean 定义的名称。id 和 ref 元素之间的这种联系表示了两个协作对象的依赖 关系。要了解更多配置对象依赖的信息,可以参考依赖(4.4 节)。 4.2.2.1 处理基于 XML 的配置元数据 跨越多个 XML 文件中定义 bean 是很有用的。通常每个独立的 XML 配置文件代表了一 个逻辑层或架构中的一个模块。 你可以使用 ApplicationContext 的构造方法从所有的 XML 文件片段中来加载 bean。这个 构造方法可以接收多个 Resource 位置,这在之前的部分都已经看到了。另外,可以使用一 个或多个元素来从另外的一个或多个文件中加载 bean。比如: 在 这 个示 例 中, 外部 的 bean 通过三个文件来加载,分别是 services.xml, messageSource.xml 和themeSource.xml。所有的位置路径都是相对于该引用文件的, 所以 service.xml 必须在和引用文件相同路径中或 者 是 类 路 径 下 , 而 messageSource.xml 和 themeSource.xml 必须是在位于引用文件下一级的 resources 路径下。正如你看到的,前部的斜杠被忽略了,这是由于路径都是相对的,最 好就不用斜线。文件的内容会被引入,包括顶级的元素,根据 Spring 的 Schema 或 DTD,它必须是有效 bean 定义的 XML 文件。 注意 在父目录中使用相对路径“../”来引用文件,这是可能的,但是不推荐这么做。这么做 了会创建一个文件,它是当前应用程序之外的一个依赖。特别是,这种引用对于 “classpath:”的 URL(比如,“classpath:../service.xml”)是不推荐的,运行时的解析过 程会选择“最近的”类路径根目录并且会查看它的父目录。类路径配置的修改可能会导 致去选择一个不同的,不正确的目录。 你也可以使用资源位置的完全限定名来代替相对路径:比如,“file:C:/config/services.xml” 或“classpath:/config/services.xml”。这样的话,要注意你会耦合应用程序的配置到指定 的绝对路径。对于绝对路径,一般最好是保持一个间接的使用,比如通过占位符“${...}”, 这会基于运行时环境的 JVM 系统属性来解决。 4.2.3 使用容器 ApplicationContext 是能维护不同的 bean 和它们依赖注册的高级工厂接口。使用 T getBean(Stringname, Class requiredType)方法你可以获取 bean 的实例。 ApplicationContext 允许你读取 bean 并且访问它们,如下所示: 使用 getBean()方法来获取 bean 的实例。ApplicationContext 接口有一些其它 // 创建并配置bean ApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"services.xml", "daos.xml"}); // 获取配置的实例 PetStoreServiceImpl service = context.getBean("petStore", PetStoreServiceImpl.class); // 使用配置的实例 List userList service.getUsernameList(); 方法来获取 bean,但最好应用程序代码不使用它们。事实上,应用程序代码应该没有 getBean()方法的调用,那么就没有对 Spring API 的依赖了。比如,Spring 和 Web 框架整 合时,提供了对各种 Web 框架类库的依赖注入,不如控制器和 JSF 管理的 bean。 4.3 Bean 概述 Spring 的 IoC 容器管理一个或多个 bean。这些 bean 通过提供给容器的配置元数据被创 建出来,比如,在 XML 中的定义的形式。 在容器本身,这些 bean 代表了 BeanDefinition 对象,它们包含(在其它信息中) 下列元数据:  打包的类限定名:就是这些 bean 的真正实现类。  bean 的行为配置元素,这表示了 bean 在容器中(范围,生命周期回调等等)应该是怎 样的行为。  对其它 bean 的引用,这是该 bean 工作所需要的;这些引用通常被称为合作者或依赖。  在新被创建的对象中的其它配置设置,比如,管理连接池的 bean 中使用的连接数或连 接池限制的大小。 元数据翻译成一组属性集合来构成每一个 bean 的定义。 表格 4.1 bean 定义 属性 解释章节 class 4.3.2 节,“实例化 bean” name 4.3.1 节,“命名 bean” scope 4.5 节,“bean 的范围” constructor arguments 4.4.1 节,“依赖注入” properties 4.4.1 节,“依赖注入” autowiring mode 4.4.5 节,“装配合作者” lazy-initialization mode 4.4.4 节,“延迟初始化 bean” initialization method 4.6.1.1 节,“初始化回调” descruction method 4.6.12 节,“销毁调用” 此外,bean 的定义还包含如何创建特定 bean 的信息,ApplicationContext 的实现 类允许用户将容器外部创建的已有对象的注册。这可以通过 getBeanFactory()方法访问 ApplicationContext 的 BeanFactory 来完成, 它 会 返 回 BeanFactory 的实现类 DefaultListableBeanFactory 。 DefaultListableBeanFactory 通过 registerSingleton(..)和 registerBeanDefinition(..)方法来支持这种注册。 而典型的应用程序只和通过元数据定义的 bean 来工作。 4.3.1 命名 bean 每个 bean 有一个或者多个标识符。这些标识符必须在托管 bean 的容器内唯一。通常 一个 bean 只有一个标识符,但如果它需要多个的话,其它的可以被认为是别名。 在基于 XML 的配置元数据中,你可以使用 id 和/或 name 属性来指定 bean 的标识符。 id 属性允许你指定一个准确的 id。按照管理这些名称是字母和数字(‘myBean’,‘fooService’ 等),但是可能是特殊字符。如果你想为 bean 引入别名,你也可以在 name 属性中来指定, 通过逗号(,),分号(;)或空格来分隔。作为对历史的说明,在 Spring 3.1 版之前,id 属性 是 xsd:ID 类型,只限定为字符。在 3.1 版本中,现在是 xsd:string 类型了。要注意 bean 的 id 的唯一性还是被容器所强制的,但是对于 XML 处理器却不是。 当然你也可以不给 bean 提供 name 或 id。如果没有提供明确的 name 或 id,那么容器 会为这个 bean 生成一个唯一的名称。然而,如果你想通过名称来参考这个 bean,那么可以 使用 ref 元素或者是服务定位器(4.15.2 节)风格的查找,你必须提供一个名称。不提供 名称的动机是和使用内部 bean(4.4.2.3 节)或自动装备合作者(4.4.5 节)相关的。 4.3.1.1 在 bean 定义外面起别名 在 bean 定义的本身,你可以为 bean 提供多于一个的名称,使用一个由 id 属性或 name 属性中的任意名称数指定的名称组合。这些名称对于同一个 bean 来说都是相等的别名,在 一些情况下,这是很有用的,比如在应用程序中允许每个组件参考一个共同的依赖,可以使 用为组件本身指定的 bean 的名称。 然而,在 bean 定义时指定所有的别名是不够的。有事可能想在任意位置,为一个 bean 引入一个别名。这在大型系统中是很常见的例子,其中的配置信息是分在每个子系统中的, 每个子系统都有它自己的对象定义集合。在基于 XML 的配置元数据中,你可以使用 元素来完成这项工作。 在这个示例中,在相同容器中的名称为 fromName 的 bean,在使用过这个别名定义后, 也可以使用 toName 来指引。 比如,在子系统的配置元数据中,A 可能要通过名称‘subsystemA-dataSource’来指向 数据源。为子系统 B 的配置元数据可能要通过名称‘subsystemB-dataSource’来指向数据源。 当处理使用了这两个子系统的主程序时,主程序要通过名称‘myApp-dataSource’来指向数 据源。那么就需要三个名称指向同一个对象,那么就要按照下面的别名定义来进行添加 MyApp 的配置元数据: 现在每个组件和主程序都可以通过一个唯一的保证不冲突的名称来还有其它任意定义 (更有效地是创建命名空间)来参照数据源了,当然它们参照的是同一个 bean。 Bean 的命名约定 该约定是用于当命名 bean 时,对实例字段名称的标准 Java 约定。也就是说,bean 的名称以小写字母开始,后面是驼峰形式的。这样的命名可以是(没有引号) ‘accountManager’,‘ accountService’,‘ userDao’,‘ loginController’ 等。 一致的命名 bean 可以使你的配置信息易于阅读和理解,如果你使用 Spring 的 AOP, 当应用通知到一组相关名称的 bean 时,它会给你很大的帮助。 4.3.2 实例化 bean bean 的定义信息本质上是创建一个或多个对象的方子。当需要一个 bean 时,容器查找 这些方子来查找命名的bean,并且使用由 bean定义信息封装的配置元数据来创建(或获得) 一个真实的对象。 如果你使用基于 XML 的配置元数据,你为要被实例化的对象所指定的类型(或类)是 元素中 class 属性。这个 class 属性,是 BeanDefinition 实例内部的 class 属性,通常是强制要有的。(对于特例,可以参考 4.3.2.3 节,“使用实例的工厂方法来实例 化”和 4.7 节,“Bean 定义的继承”)你可以以两种方法之一来使用 class 属性:  典型的是,指定要被构造的 bean 类,容器本身直接通过反射调用它的构造方法来创建 bean,也就是和 Java 代码中使用 new 操作符是相同的。 指定包含 static 工厂方法的真实的类,会被调用来创建对象,在一些不太常见的情况下, 容器会调用类的 static 工厂方法来创建 bean。从调用 static 工厂方法返回的对象类型可能 是和另外一个类完全相同的类。 4.3.2.1 使用构造方法实例化 当你使用构造方法来创建 bean 时,所有普通的类的使用都和 Spring 兼容。也就是说, 开发中的 bean 不需要实现任何特定的接口或以特定的方式来编码。仅简单指定 bean 的类 就足够了。但基于你使用的是什么类型的 IoC,就可能需要一个默认(空的)构造方法。 Spring 的 IoC 容器可以虚拟地管理任意的你想让它管理的类;而不仅仅限于管理真正的 JavaBean。很多Spring 用户喜欢在容器中使用有默认(无参数)构造方法和在其后有适当setter 和 getter 方法的真正 JavaBean。你也可以在容器中使用很多异样的,非 bean 样式的类。比 如,需要使用遗留的连接池,但是它没有符合 JavaBean 的规范,Spring 也能照样管理它。 基于 XML 的配置元数据,你可以如下来定义 bean: 关于提供构造方法参数(如果需要)和在对象被构造后,设置对象实例属性机制的详情, 请参考 4.4.1 节依赖注入。 4.3.2.2 使用静态工厂方法来实例化 当使用静态工厂方法来定义 bean 的时候,可以使用 class 属性来指定包含 static 工厂 方法的类,而名为 factory-method 的属性来指定静态方法。你应该调用这个方法(还可 以有可选的参数)并返回一个实际的对象,随后将它视为是通过构造方法创建的一样。在遗 内部类名称 如果你想为 static 嵌入的类配置 bean,你需要使用内部类的二进制名称。 比如,如果在 com.example 包下有一个 Foo 类,而这个 Foo 类有一个 static 的内 部类 Bar,那么在定义 bean 时’class’属性的值就会是... com.example.Foo$Bar 请注意名称中$符号的使用,用来从外部类名中分隔内部类名。 留代码中,这样定义 bean 的使用方式之一是调用 static 工厂。 下面 bean 的定义指定了要通过调用工厂方法生成的 bean。这个定义没有指定返回对象 的类型(类),仅仅是包含工厂方法的类。在本例中,createInstance()方法必须是静 态方法。 关于提供(可选的)参数到工厂方法并在对象由工厂返回后设置对象实例属性的机制详 情,请参考 4.4.2 节深入依赖和配置。 4.3.2.3 使用实例工厂方法来实例化 和使用静态工厂方法(4.3.2.2 节)实例化相似,使用实例工厂方法实例化是要调用容器 中已有 bean 的一个非静态的方法来创建新的 bean。要使用这个机制,请把 class 属性留 空,但在 factory-bean 属性中指定当前(或父/祖先)容器中 bean 的名字,该 bean 要 包含被调用来创建对象的实例方法。使用 factory-method 方法来设置工厂方法的名称。 public class ClientService { private static ClientService clientService = new ClientService(); private ClientService() {} public static ClientService createInstance() { return clientService; } } public class DefaultServiceLocator { private static ClientService clientService = new ClientServiceImpl(); private DefaultServiceLocator() {} public ClientService createClientServiceInstance() { return clientService; } } 一个工厂类也可以有多于一个工厂方法,比如下面这个: 这个方法展示了工厂 bean 本身可以通过依赖注入(DI)被管理和配置。请参考 4.4.2 节 深入依赖和配置。 注意 在 Spring 文档中,工厂 bean 指的是在 Spring 容器中配置的 bean,可以通过实例(4.3.2.3 节)或静态(4.3.2.2 节)工厂方法来创建对象。与此相反的是,FactoryBean(注意大小 写)指的是 Spring 特定的 FactoryBean(4.8.3 节) 4.4 依赖 典型的企业级应用程序不是由单独对象(或 Spring 中的 bean)构成的。尽管最简单的 应用程序有一些对象协同工作来表示终端用户所看到的连贯的应用。下一节会解释如何去为 完全实现的应用程序定义一组独立的 bean,其中对象间相互协作来达到目标。 4.4.1 依赖注入 依赖注入(DI)是对象定义它们依赖的过程,也就是说,要和它们协同工作其它对象, 仅仅可以通过构造方法参数,工厂方法参数,或者是在工厂方法返回的对象或被构造好后, public class DefaultServiceLocator { private static ClientService clientService = new ClientServiceImpl(); private static AccountService accountService = new AccountServiceImpl(); private DefaultServiceLocator() {} public ClientService createClientServiceInstance() { return clientService; } public AccountService createAccountServiceInstance() { return accountService; } } 为对象实例设置的属性。容器当创建好 bean,随后就会注入那些依赖。这个过程从根本上 来说是反向的,因此命名为控制反转(IoC), bean 本身直接使用构造好的类或服务定位器 模式来控制实例或它的依赖的所在位置。 应用了 DI 原则,代码就干净多了,当为对象提供它们依赖的时候,解耦是很有效率的。 对象不再去检查它的依赖,也不需要知道位置或依赖的类。因此,类就很容易被测试,特别 是当依赖是接口或抽象基类的时候,这允许在单元测试中使用 stub 或 mock 的实现类。 DI 存在两种主要的方式,基于构造方法的依赖注入(4.4.1.1 节)和基于 setter 方法的依 赖注入(4.4.1.2 节)。 4.4.1.1 基于构造方法的依赖注入 基于构造方法的依赖注入是容器调用构造方法和一组参数完成的,每个都表示着一个依 赖。使用特定的参数来调用 static 工厂方法构造 bean 基本也是相同的,这种说法把给构 造方法的参数和给 static 工厂方法的参数相类似。下面的示例展示了一个仅使用构造方 法进行依赖注入的饿类。注意这个类没有什么特殊之处,就是一个 POJO 而且没有对容器特 定接口,基类或注解的依赖。 构造方法参数解析 构造方法参数解析匹配使用参数的类型。如果在 bean 的构造方法参数不存在潜在的歧 义,那么当 bean 被实例化的时候,定义的构造方法参数的顺序就是被提供到适当构造方法 参数的顺序。请看下面的类: 没有潜在的歧义存在,假设 Bar 和 Baz 类没有继承关系。因此下面的配置就可以使用 了,而且并不需要明确地在元素中去指定构造方法参数的索引和/ 或类型。 public class SimpleMovieLister { // SimpleMovieLister对MovieFinder有依赖 private MovieFinder movieFinder; // 这个构造方法使得Spring容器可以’注入’MovieFinder public SimpleMovieLister(MovieFinder movieFinder) { this.movieFinder = movieFinder; } // 业务逻辑就可以’使用’注入的MovieFinder了,代码就省略了... } package x.y; public class Foo { public Foo(Bar bar, Baz baz) { // ... } } 当另外一个 bean 被引用时,类型是明确的,那么匹配就能成功(前面示例中也是这样 的)。当使用简单类型时,比如true,Spring 不能决定值的类型,所以 没有帮助是不能匹配的。看下面的示例: 构造方法参数类型匹配 在上面的情形下,如果你使用 type 属性明确地为构造方法参数指定类型的话,容器可 以进行匹配简单的类型。比如: 构造方法参数索引 使用 index 属性来指定明确的构造方法参数索引。比如: 此外,为了解决多个简单值的歧义,如果构造方法有两个相同类型的参数时,指定所以 可以解决歧义。注意索引是基于 0 开始的。 构造方法参数名称 在 Spring 3.0 中,你也可以使用构造方法参数名称来消除歧义: package examples; public class ExampleBean { // 计算最佳答案的年数 private int years; // 生命,宇宙,所有问题的答案 private String ultimateAnswer; public ExampleBean(int years, String ultimateAnswer) { this.years = years; this.ultimateAnswer = ultimateAnswer; } } 要记住要使得这种方式可用,代码必须和内嵌的调试标识一起编译,那样 Spring 才可 以从构造方法中来查找参数。如果没有和调试标识(或不想)一起编译,那么可以使用 JDK 的注解@ConstructorProperties 来明确构造方法参数。那么示例代码就如下所示: 4.4.1.2 基于 setter 方法的依赖注入 基于setter 方法的依赖注入由容器在调用过无参数的构造方法或无参数的static工厂 方法来实例化 bean 之后,再调用 bean 的 setter 方法来完成的。 下面的示例展示了一个仅仅能使用纯 setter 方法进行依赖注入的类。这是一个常见的 Java 类,是一个没有依赖容器指定的接口,基类或注解的 POJO。 ApplicationContext对它管理的bean支持基于构造方法和 setter 方法的依赖注入。 也支持在一些依赖已经通过构造方法注入之后再进行 setter 方 法 注 入 。 以 BeanDefinition 形式来配置依赖,使用 PropertyEditor 实例将属性从一种形式格式 化到另一种。但很多 Spring 的用户不直接(编程时)使用这些类,而是使用 XML 文件来定 义,之后会在内部转换这些类的实例,需要加载整个 Spring IoC 容器的实例。 package examples; public class ExampleBean { // 忽略属性 @ConstructorProperties({"years", "ultimateAnswer"}) public ExampleBean(int years, String ultimateAnswer) { this.years = years; this.ultimateAnswer = ultimateAnswer; } } public class SimpleMovieLister { // SimpleMovieLister对MovieFinder有依赖 private MovieFinder movieFinder; // setter方法可以让Spring容器来'注入'MovieFinder public void setMovieFinder(MovieFinder movieFinder) { this.movieFinder = movieFinder; } // 真正’使用’注入的MovieFinder的业务逻辑代码被省略了... } 4.4.1.3 解决依赖过程 容器按如下步骤来解决 bean 的依赖: 1. ApplicationContext 和描述了所有 bean 的配置元数据一起被创建并初始化。配 置元数据可以通过 XML,Java 代码或注解来指定。 2. 对于每一个 bean 来说,它的依赖被表述为属性,构造方法参数的形式,如果你使用 了静态工厂方法来代替构造方法,那么还会是静态工厂方法参数的形式。当 bean 被实际创 建时,这些依赖被提供给 bean。 3. 每个属性或构造方法参数就是一个要被设置的值或者是容器中其它 bean 的引用。 4. 每个属性或构造方法参数值会被转换特定格式的形式,去匹配属性或构造方法参数 的类型。默认情况下,Spring 可以转换给定的字符串格式的值到内建的类型,比如 int,long, String,boolean 等。 当容器被创建时,Spring 容器会来验证每个 bean 的配置,包括验证 bean 的引用属性是 否是一个合法的 bean。然而,bean 属性本身直到 bean 真正被创建出来后才被设置进去。 当容器被创建时,bean 的范围是单例时,会被设置成预实例(默认情况)来创建。范围在 4.5 节,“bean 的范围”部分来解释。否则,bean 就会当被请求的时候被创建。一个 bean 的创建潜在地会引起一系列 bean 被创建,因为 bean 的依赖和它依赖的依赖(等等)要不 创建和定义出来。 基于构造方法还是 setter 方法进行依赖注入? 因为你可以将二者混淆,那么对于基于构造方法或是 setter 方法的依赖注入,有一 个很好的规则就是为强制依赖使用构造方法参数,而对于可选参数使用 setter 方法。要 注意在 setter 方法上使用注解@Required(4.9.1 节),可用于 setter 方法所需的依赖。 Spring 团队通常主张使用 setter 方法注入,因为大量的构造方法参数会使程序变得非 常笨拙,特别是当属性为可选的时候。Setter 方法会让该类的对象今后适合于重新配置或 重新注入。通过 JMX Mbean(第 23 章)来管理就是一个令人关注的用例。 一些人纯粹赞成构造方法注入。提供所有对象的依赖意味着对象在完全初始化状态 时,通常要返回客户端(调用)代码。这个缺点会使得对象变得不适合去重新配置或重 新注入。 使用依赖注入的时候要特别注意一些类。当要选择处理没有源代码时的第三方类库 的时候。遗留的类可能没有暴露任何 setter 方法,而构造方法注入则是唯一可用的依赖 注入方式。 循环依赖 如果你使用主要的构造方法注入,就可能会引起不可解决的循环依赖情形。 比如,类 A 需要通过构造方法注入获得类 B 的实例,而类 B 也需要通过构造方法注 入获得类 A 的实例。如果把类 A 和类 B 进行相互注入,Spring 的 IoC 容器会在运行时检 测到这是循环引用的情况,并且抛出 BeanCurrentlyInCreationException 异常。 一个可行的方案是编辑一些要配置的类的源码,通过 setter 方法而不是构造方法进 行注入。而且,避免构造方法注入并仅仅使用 setter 方法注入。换句话说,尽管这不是 推荐做法,你可以通过 setter 方法注入来配置循环依赖。 不像典型的用例(没有循环依赖),在 bean A 和 bean B 之间的循环依赖强制一个 bean 被注入到另一个中会先于被完全初始化自己(就是经典的鸡和蛋的问题)。 通常情况下你可以信任 Spring 做出正确的事情。它会在容器加载时来检测配置问题, 比如引用了一个不存在的 bean 和循环依赖问题。当 bean 被实际创建出来后,Spring 设置属 性和解决依赖会尽量地晚些。这就意味着 Spring 容器已经加载正确了但晚些时候可能会生 成异常,比如当你请求一个创建时发生问题的对象或者是它的依赖发送问题。例如,bean 因为丢失或非法属性而抛出异常。这种潜在的一些配置问题的可见度延迟也就是为什么 ApplicationContext 的实现类默认情况都是预实例的单例 bean。在前期的时间和内存 消耗中,在 bean 真正需要前来创建这些 bean,当 ApplicationContext 被创建的时候, 你会发现这些配置问题,这还不晚。你也可以覆盖这个默认的行为,那么单例 bean 就会延 迟加载,而不是预实例的了。 如果没有循环依赖的存在,当一个或多个协作的 bean 被注入到一个独立的 bean 时, 每个协作的 bean 就会在被注入之前完全被配置好。这就意味着如果 bean A 对 bean B 有依 赖,那么 Spring 的 IoC 容器会完全配置 bean B 而优先于调用 bean A 中的 setter 方法。换句 话说,bean 被实例化了(而不是预实例的单例 bean),它的依赖才被注入,相关的生命周 期方法(比如配置初始化方法(4.6.1.1 节)或初始化 bean 的回调方法(4.6.1.1 节))才被 调用。 4.4.1.4 依赖注入示例 下面的示例使用了基于 XML 的配置元数据来进行基于 setter 方法的依赖注入。Spring XML 配置文件的一小部分来指定几个 bean 的定义: public class ExampleBean { private AnotherBean beanOne; private YetAnotherBean beanTwo; private int i; public void setBeanOne(AnotherBean beanOne) { this.beanOne = beanOne; } public void setBeanTwo(YetAnotherBean beanTwo) { this.beanTwo = beanTwo; } public void setIntegerProperty(int i) { this.i = i; } } 上面的示例中,setter 方法被声明为匹配 XML 文件中指定的属性。下面的示例使用基于 构造方法的依赖注入: 在 bean 中指定的构造方法参数会被用于 ExampleBean 的构造方法参数。 现在考虑一下这个示例的变化情况,要代替使用构造方法,Spring 被告知调用 static 工厂方法并返回一个对象的实例: public class ExampleBean { private AnotherBean beanOne; private YetAnotherBean beanTwo; private int i; public ExampleBean(AnotherBean anotherBean, YetAnotherBean yetAnotherBean, int i) { this.beanOne = anotherBean; this.beanTwo = yetAnotherBean; this.i = i; } } static 工厂方法的参数通过元素来提供,这和构造方法已经 被实际调用是完全一致的。由工厂方法返回的类的类型不需要和包含 static 工厂方法类 的类型相同,尽管在本例中是相同的。实例(非静态)工厂方法可以被用于本质上相同的方 式(除了 factory-bean 属性的使用,来代替 class 属性),所以这里不讨论它们的细节。 4.4.2 深入依赖和配置 正如之前章节中所提到的,你可以定义 bean 的属性和构造方法参数作为其它被管理 bean(协作者)的引用,或者作为内联值的定义。出于这个目的,Spring 的基于 XML 的配 置元数据支持使用元素的子元素类型。 4.4.2.1 直接值(原生类型,String,等) 元素的 value 属性指定了属性或构造方法参数,这是人们可以阅读的 字符串的表达。正如之前提到过的(6.4.2 节),JavaBean 的 PropertyEditor 可以用来转 换这些字符串值从 String 到属性或参数的真实类型。 对于更简洁的 XML 配置,下面的示例使用了 p-命名空间(4.4.2.6 节)。 public class ExampleBean { // 私有的构造方法 private ExampleBean(...) { ... } // 静态工厂方法; 这个方法的参数可以被认为是要返回bean的依赖, // 而不管那些参数是如何被使用的。 public static ExampleBean createInstance (AnotherBean anotherBean, YetAnotherBean yetAnotherBean, int i) { ExampleBean eb = new ExampleBean (...); // 其它的操作... return eb; } } 上面的 XML 非常简洁;然而,错误之处会在运行时被发现而不是设计的时候,除非在 你创建 bean 的时候,使用如 IntelliJ IDEA 或 SpringSource Tool Suite(STS,SpringSource 组织 开发的工具套件)这样的 IDE 来支持自动地属性补全。这样的 IDE 帮助是强烈建议使用的。 你也可以这样来配置 java.util.Properties 实例: Spring 容器会使用 JavaBean 的 PropertyEditor 机制来转换元素中的文本 到 java.util.Properties 实例。这是一个很好的捷径,也是 Spring 团队少有喜欢使用 嵌套的元素而不是 value 属性方式的地方之一。 idref 元素 idref 元素是一种简单防错的形式来传递容器中另外一个 bean 的 id(字符串值而不是 引用)到元素中。 jdbc.driver.className=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/mydb 上面定义 bean 的代码片段是和下面的片段完全等价(在运行时): 第一种形式比第二种形式可取,因为使用 idref 标签允许容器在部署时来验证被引用 的,命名的 bean 是否真的存在。第二种形式下,没有对传递给 client bean 的 targetName 属性执行验证。错误仅仅是在 client bean 被真正实例化的时候才会被发现(和很多可能 致命的结果)。如果 client bean 是 prototype(4.5 节)类型的 bean,这个错误和结果异常 可能仅仅在容器被部署很长一段时间后才会被发现。 此外,如果被引用的 bean 在同一个 XML 单元中,bean 的名称就是 bean 的 id,那么你 还可以使用 local 属性,这允许 XML 解析器本身在 XML 文档解析的时候,及早地来验证 bean 的 id。 元素带来的一个相同之处(最少是 Spring 2.0 版 本 以 前 的 ) 是 值 在 ProxyFactoryBean 定义的 AOP 拦截器的配置中。当你指定拦截器名称来防止拼错拦截 器的 id 时,可以使用元素。 4.4.2.2 引用其它 bean(协作者) ref 元素是定义元素中最后的一个。在这里 你可以为 bean 设置指定属性的值,来引用被容器管理的另外一个 bean(协作者)。被引用 的 bean 就是要设置属性的这个 bean 的一个依赖,并且是初始化的作为属性设置之前的点 播。(如果协作者是一个单例的 bean,它可能已经被容器初始化过了。)所有引用最终都会 被引用到一个对象中。范围和验证基于通过 bean,local 或 parent 属性指定 id/name 的其它对象。 通过标签的 bean 属性来指定目标 bean 是最常用的方式,并允许创建引用到相 同容器或父容器的任意 bean 中,而不管它们是不是在同一个 XML 文件中。bean 属性的值 可能和目标 bean 的 id 属性相同,或者是目标 bean 的 name 属性值之一。 通过 local 属性来指定目标 bean 是利用了 XML 解析器的能力,来验证 XML 相同文件 内的 id 引用。local 属性的值必须和目标 bean 的 id 属性一致。如果没有在相同的文件内 发现匹配的元素,那么 XML 解析器会报告问题。因此,如果目标 bean 在同一个 XML 文件 中的话,使用 local 这种形式是最佳选择(为了更早地知道错误)。 通过 parent 属性来指定目标 bean 会为 bean 创建引用,它是在当前容器的父容器中 的。parent 属性的值可能和目标 bean 的 id 属性相同,或者是目标 bean 的 name 属性值 之一,而且目标 bean 必须在当前容器的父容器中。当有一个容器继承关系,可以使用这个 bean 的引用,或在你想使用和父 bean 有相同名称的代理包装一个父容器中已有 bean 时。 4.4.2.3 内部 bean 在元素内部的元素的定义被称为 内部 bean。 内部 bean 的定义不需要定义 id 或 name;容器忽略这些值。也会忽略 scope 标识。内 部 bean 通常是匿名的,而且范围通常是 prototype(4.5.2 节)的。注入内部 bean 到协作 bean 是不可能的,只能到包围它的 bean 中。 4.4.2.4 集合 在元素中,你可以分别设置 Java 的 Collection 类型 List,Set,Map 和 Properties 的属性和参数。 class="org.springframework.aop.framework.ProxyFactoryBean"> Map 类型的 key 或 value 的值,或 set 的值,也可以是下列元素之一: 集合合并 在 Spring 2.0 中,容器支持集合的合并。应用开发人员可以定义父样式的元素,子样式的 元素继承或重写来自父集合的值。也就是说,子集合的值是合并元素父与子集合中的元素, 和子集合元素覆盖父集合中指定值的结果。 本节关于导论父子 bean 合并的机制。如果读者不熟悉父和子 bean 的定义,可能要先去 阅读一下相关章节(4.7 节)。 下面的示例说明了集合合并: administrator@example.org support@example.org development@example.org a list element followed by a reference just some string bean | ref | idref | list | set | map | props | value | null 注意在 child bean 中的 adminEmails 属性下的元素中的 merge=true 属性的使用。当 child bean 被容器处理并实例化时,结果实例中有一个 adminEmails Properties 的 集 合 , 包 含 了 合 并 子 bean 的 adminEmails 集合和父 bean 的 adminEmails 集合。 子 bean 的 Properties 集合的值设置继承了从父元素而来的所有属性,子 bean 中 support 的值覆盖了父 bean 中的值。 这种合并行为的应用和集合类型很相似。在元素特 定的情形下,和 List 集合类型相关的语义,也就是说,ordered 集合值的概念,是要维 护的;父值优先于所有子 list 的值。在 Map,Set 和 Properties 集合类型的情况下,没 有顺序的存在。因此对于容器内部使用的,和 Map,Set 和 Properties 实现类型相关的 集合类型没有排序语义的作用。 集合合并的限制 不能合并不同类型的集合(比如 Map 和 List),如果你要尝试这么去做,那么就会抛 出 Exception。merge 属性必须在低级的,继承的,子 bean 中来指定;在父集合中指定 merge 属性是冗余的,也不会看到想要的合并结果。合并特性仅在 Spring 2.0 和更高版本中 可用。 强类型集合(Java 5 以上版本) 在 Java 5 或更高版本中,你可以使用强类型集合(使用泛型)。也就是说,可以声明一 个 Collection 类型,它可以仅仅包含 String 元素(作为示例)。如果你使用 Spring 来 administrator@example.com support@example.com sales@example.com support@example.co.uk administrator=administrator@example.com sales=sales@example.com support=support@example.co.uk 对强类型的 Collection 依赖注入到 bean 中,你可以利用 Spring 的类型转换来支持这样 强类型 Collection 实例的元素,在被加到 Collection 之前,可以转换成合适的类型。 当foo bean的accounts属性准备好注入时,关于强类型元素Map 类型的泛型信息就通过反射机制准备好了。因此 Spring 的类型转换工具识别到各种元素的 值作为 Float 类型,字符串值 9.99,2.75 和 3.99 被转换成实际的 Float 类型。 4.4.2.5 null 和空字符串 Spring 将属性的空参数当作空 String。下面基于 XML 的配置元数据片段设置了电子邮 件属性为空 String 值("")。 上面的例子和下面的 Java 代码是一样的:exampleBean.setEmail("")。 元素控制 null 值。比如: 上面的配置和下面的 Java 代码一致:exampleBean.setEmail(null)。 public class Foo { private Map accounts; public void setAccounts(Map accounts) { this.accounts = accounts; } }
还剩49页未读

继续阅读

下载pdf到电脑,查找使用更方便

pdf的实际排版效果,会与网站的显示效果略有不同!!

需要 10 金币 [ 分享pdf获得金币 ] 1 人已下载

下载pdf

pdf贡献者

nbnw

贡献于2016-01-23

下载需要 10 金币 [金币充值 ]
亲,您也可以通过 分享原创pdf 来获得金币奖励!
下载pdf