Spring 5 中文解析核心篇-IoC容器之IoC容器和Bean概述
关于本书
本书
本书编写主要目的在于翻译官方关于模块文档之核心篇,但是本书不仅仅是简单的翻译,我会根据相应的模块给出一些代码的操作实践以及给出相应的源码分析,文档我个人认为在所有开源框架中算是写得最好的了,But如果对于初学者或者是实践经验较少的小伙伴来说还是比较困难的。这里不仅仅是文档全是英文形式而且根据文档的概述是比较难理解和应用到实践项目开发中,这里需要开发人员积累了相应的项目实践经验才行。So我在翻译过程中会不断编写相应的示例代码、结合文档和源码分析达到更好的理解。在后面的书中我可能会翻译现在比较流行的微服务框架 、以及Spring的其他模块比如:、、 等,在整个Spring体系中起着基石的作用,基于进行了相应的拓展包括:、、等,而基于对整个微服务体系的服务治理、服务注册发现、统一配置中心等做了相关的集成和统一相关的抽象例如: 等。对应这块主要分为以下模块来解析:、、、、、。
版本
当前选择的版本进行分析。
约束
使用字体加粗对重点关键字进行标注
使用灰色线框对专业术语进行标识
本文使用不同层级对文档结构进行描述
文章的一级、二级分类尽量保存英文不做翻译(能够帮助读者能够快速定位原文位置)
本书开始编写时间2020-05-05
作者
个人从事金融行业,就职过易极付、思建科技、某网约车平台等重庆一流技术团队,目前就职于某银行负责统一支付系统建设。自身对金融行业有强烈的爱好。同时也实践大数据、数据存储、自动化集成和部署、分布式微服务、响应式编程、人工智能等领域。同时也热衷于技术分享创立公众号和博客站点对知识体系进行分享。
微信公众号:

概述
使得开发人员更加容易的创建企业级应用程序,它提供了在企业Java生态技术栈中的任何技术体系,同时也提供了和对JVM的支持,并且可以根据应用程序的需要灵活地创建多种体系结构,从开始需要JDK1.8+,同时也提供了对JDK 11 LTS开箱即用的支持。作为Java 8最低的补丁版本被建议使用,但是一般推荐使用最近发布的补丁版本。
支持广泛的应用场景。在大型企业中,应用程序可能长时间的存在,而且需要运行在JDk上,同时应用程序的升级维护生命周期不受开发人员的控制。其他可能作为单独的jar运行或者嵌入式运行,也可能运行在云环境中。也可能是不需要服务器的一个独立的应用程序(例如:批处理、集成负载)。
和和一样可以编译成JVM支持的字节码格式,运行在JVM中。
是一个开源的框架。拥有一个非常强大和活跃的社区,它提供了一个范围广泛的实际应用案例的持续反馈。这有助于长时间的成功发展。
What We Mean by "Spring"
术语在不同上下文意义是不同。在这里就是指项目本身。然而随着时间的推移,其他的项目被构建在基础上。大多数情况下,我们所说的是包括整个项目体系。这篇文档主要聚焦在框架本身。
分为多个模块。应用程序根据需要选择合适的模块。核心容器的模块是核心包括:配置模型、依赖注入机制。除此之外,提供一些基础的为不同应用架构、消息、事务数据和持久化、web提供支持。它也包括了基于Servlet基础的SpringMVC的web框架和支持的reactive编程模型的web框架。
关于模块需要注意的:的这些框架jar包允许被部署到JDK9的模块路径。为了在支持的应用程序中使用, jar附带了清单条目,这些清单条目定义了与jar无关的稳定语言级别的模块名称(,等)名称(这些jar遵循相同的命名模式,用代替,例如和)。当然,Spring的框架jar可以在JDK 8和9的类路径上正常工作。
History of Spring and the Spring Framework
介于早期的规范过于复杂,在2003年诞生了,尽管有些人认为Java EE和竞争,但事实上是Java EE的补充。编程模型不包含Java EE平台规范。相反,它精心选择各个规范进行集成
JTA/JCA(分布式事务)
同时也支持依赖注入()和通用注解规范 () ,应用程序开发人员可以选择使用这些规范来代替Spring框架提供的特定于Spring的机制。
从后,的最低要求 Java EE 7(, )同时提供了开箱即用的集成Java EE 8最新的API (),这样使得能够更好的兼容例如: 、 , , 服务容器。
随着时间的推移,在应用开发中的作用已经发生改变。在J2EE和的早期,应用程序需要部署到应用服务器上。如今,在的帮助下,这些应用可以通过和友好的方式被创建,同时通过容器的嵌入和一些很小的改变。从开始的应用程序甚至不需要直接使用的API并且能够直接运行在非容器服务器上。
不断的创新和发展。除了,还有其他项目,例如,,,,等。请务必记住,每个项目都有自己的源代码存储库,问题跟踪程序和发布节奏。请查看 罗列了完整的项目清单。
Design Philosophy(哲学)
当你在学习框架的时候,最重要的是不仅仅知道它能做什么,而且要遵循什么原则。以下是框架的指导原则。
Spring提供在各个级别的选择。让开发者尽可能的推迟对设计的抉择。例如:你可以在不更改代码的情况下使用配置来切换数据的持久化方案。对于其他许多基础架构问题以及与第三方API的集成也是一样可以通过配置来调整。
容纳不同的观点。支持灵活性,对于事情应该如何完成没有任何意见。它支持具有不同视角的广泛应用程序需求(备注:意思是设计相当灵活、对应怎样去完成逻辑处理不会干涉)
Spring保存了强的向后兼容性。Spring的演进被精心的管理以确保在不同版本间的变更尽量小。Spring非常小心的选择JDK和第三方库的版本,以方便维护依赖于Spring的应用程序和库。
Spring的API精心设计。Spring花费了大量的时间和精力来设计API,并在许多版本和很多年中都适用的API。
高标准的代码质量要求。Spring框架非常强调有意义的、当前的和准确的。它是极少数可以代码结构整洁且程序包之间没有循环依赖关系的项目之一。
Spring核心
The IoC Container
1.1 Spring IoC容器和bean
这章节主要包括了对容器的控制反转的原理。也被称作依赖注入()。这是一个对象仅通过构造函数参数、工厂方法的参数或对象实例构造或从工厂方法返回后在对象实例上设置的属性来定义其依赖项(即与之一起工作的其他对象)的过程。此过程从根本上讲是通过使用类的直接构造或诸如服务定位器模式之类的机制来控制其依赖项的实例化或位置的bean的逆过程(因此称为)。(备注:大白话的意思就是为实例对象注入依赖的实例,注入方式包括构造函数注入、对象属性注入、方法注入等。)
和包是容器的基础。接口提供一个高级的配置机制能力,可以管理任何类型的对象。是的子接口。增加了如下能力:
更容易的集成的特性
消息资源处理(国际化)
事件发布器
应用层特定的上下文,例如:对应web应用上下文
简要来说,提供了配置框架和基本的功能,提供了更多的企业级功能。是一个完整的的超集,在这章节中只是用来描述为的容器。更多的替换的使用查看。
在中,构成你的应用程序的骨架和被容器所管理的对象被称为bean。bean是被容器所实例化、包装、和管理的对象。bean也是在我们的应用程序中许多对象中之一。bean及bean之间的依赖关系是通过容器的配置元数据反映的。
参考示例代码:
1.2 Spring IoC容器概述
接口代表的容器,同时有责任对这些bean的实例化、配置和组装。容器通过获取配置元数据知道哪些对象需要进行实例化、配置和组装。这些配置元数据通过、java的注解或者java的配置()。它允许你去表达组成应用程序的对象以及这些对象之间丰富的相互依赖关系。
在中提供了一些关于的实现。在一个独立的应用程序中,一般通过 或 去创建容器实例。而作为传统的定义配置元数据的方式,同时你可以引导容器去使用Java的注解或者Java Config作为元数据格式,通过提供少量的XML配置去声明激活这些附加元数据配置格式。
在大多数应用场景下,显示的实例化一个或多个容器实例是没有必要的。例如:在Web应用场景中,在应用程序文件中简单的xml配置描述通常就足够。如果使用Spring Tools for Eclipse工具,我们将非常容易的创建样板配置。
下面通过图片来展示是怎样工作的,我们的应用程序类(业务类)与配置元数据结合在一起,在被创建和实例化后,我们将拥有一个完整的配置和可执行的应用系统。

1.2.1 配置元数据
上图所示,容器获取配置元数据。那么这些元数据是怎样被表示或者是怎样配置的呢,作为一个开发人员,在你的应用程序中去告诉容器怎样去实例化、配置和组装这些对象。
格式作为一种传统的配置元数据方式,在这个章节中大部分内容使用这些关键概念和特性。
基于的配置元数据不是唯一被允许使用的配置方式。容器本身是和这些配置元数据是解偶的。现在,大多数的开发人员使用Java base configuration作为应用的配置方式。
关于更多的Spring容器的元数据配置方式以下罗列出来:
基于注解的配置方式:从Spring 2.5开始引入对注解元数据配置的支持
基于Java-base configuration方式:从Spring 3.0开始,的JavaConfig项目成为的核心部分,许多的特性被提供。因此,我们可以使用Java Config的方式定义外部bean而不是XML文件。我们可以使用这些新特性注解 例如: 、 、 和。
配置组成至少通常超过一个bean的定义被容器管理。基于的配置元数据将这些bean配置为顶级
这些bean的定义对应到真实的bean对象实例同时我们的应用程序由这些对象实例所构建。比如:我们定义的service层,数据存储层(dao),**展示层 ** 比如:Struts的实例、Hibernate的实例、JMS的等等。典型地,不需要在容器中配置细粒度的域对象,因为通常由DAO和业务逻辑负责创建和加载域对象。但是,你可以使用与的集成来配置在IoC容器控制范围之外创建的对象。
以下使用基于xml配置的元数据
参考示例代码:
id属性表示一个bean的唯一id
class属性表示这个bean的全路径类型名称例如:
1.2.2 容器实例化
构造函数提供了一个或多个字符串路径参数,让容器去加载外部资源的配置元数据,例如:本地文件系统或者Java 类路径等等。
ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");//加载services.xml和daos.xml配置元数据
在我们学习了关于容器后,我们可能想知道更多关于的抽象,提供了一个便利的机制去通过URI语法定义的位置读取一个输入流。特别地,被用于构建应用程序的上下文。。
以下给出服务层的元数据配置
以下显示数据获取层配置文件
在前面的实例中,服务层由类和数据存储层和对象组成(以JPA的对象关系映射为标准)。属性名称元素引用JavaBean的属性名称,并且元素引用其他bean定义的名称。id和ref之间的联系表达了协作对象的依赖性。更多的关于对象依赖的配置查看。
组成基于XML的配置元数据
Groovy的bean定义
参考示例代码:
1.2.3 容器使用
是能够维护不同bean及其依赖项的注册表的高级工厂的接口。通过使用方法可以找回我们的bean实例对象。
允许我们去读取bean的定义和获取bean实例对象,举例子:
// 创建容器和加载bean定义
ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");
// 获取bean实例
PetStoreService service = context.getBean("petStore", PetStoreService.class);
// use configured instance
List userList = service.getUsernameList();
使用Groovy配置,引导非常的类似。但是它是不同的Context的实现。举例子:
ApplicationContext context = new GenericGroovyApplicationContext("services.groovy", "daos.groovy");
最灵活的变体是结合了reader的代理-例如:通过读取XML文件中的配置信息。举例子:
GenericApplicationContext context = new GenericApplicationContext();
//加载xml中配置元数据
new XmlBeanDefinitionReader(context).loadBeanDefinitions("services.xml", "daos.xml");
context.refresh();
我们也可以使用加载Groovy配置文件。举例子:
GenericApplicationContext context = new GenericApplicationContext();
//加载groovy配置元数据
new GroovyBeanDefinitionReader(context).loadBeanDefinitions("services.groovy", "daos.groovy");
context.refresh();
我们也可以在相同的中混合或者匹配一个reader的代理,去读取不同配置源的bean定义配置信息。
我们也可以使用方法去获取我们的bean实例对象。接口同时提供了一些其他的方法获取bean实例,但是,理想情况下,我们的代码不要直接使用它们。确实,我们的应用程序代码不应该直接调用方法,这样就不会对的API进行耦合(备注:个人观点,在目前来看已经是容器管理的规范和标准了,使用API会对应用程序耦合这个两说,个人觉得是没有问题的,除非你还想换掉底层容器)。例如:集成的Web框架(一般指)提供了变体的Web框架组件的依赖注入(Controller) 和 的bean对象,同时允许我们通过元数据声明一个指定bean的依赖(例如注解注入:、)。