Spring IOC Container
All the notes are from Spring Framework 5 Doc.
一、Introduction to the Spring IOC Container and Beans
org.springframework.beans 和 org.springframework.context两个包是Spring IOC容器的基础。
BeanFactory接口提供了配置框架和基本功能,ApplicationContext接口则在此之上添加了更多满足企业应用规范的功能。
在Spring中,构成应用程序主干并由SpringIoC容器管理的"对象"称为Bean。Spring负责Bean的实例化、装配和管理(整个生命周期)。
所有Bean和它们之间的依赖关系,都反应在容器所使用的配置元数据(Configuration Metadata)中。
二、Conainer Overview
org.springframework.context.ApplicationContext代表了Spring IOC Container,因此它负责实例化、配置和装配Bean。
容器通过读取配置元数据(Configuration Metadata)获取关于要实例化、配置和组装哪些对象的说明。而配置元数据可以是XML文件、注解以及Java代码。通过它们,可以很好地表示组成应用程序的对象以及这些对象之间的丰富相互依赖关系。
如何通过这三种方式实例化ApplicationContext,在之前已经有提及过。
官方文档提到,在大多数应用程序场景中,不需要显式地用代码实例化Spring IoC容器的一个或多个实例。例如在Web应用中,最简单的做法就是在web.xml中通过ContextLoaderListener注册一个ApplicationContext。
三、Bean OverView
四、Dependencies
依赖注入(Dependency injection)是这样一个过程:
对象只通过下面的三种方式定义他们的依赖关系(即与自己一起协作的其他对象)
- 构造函数的参数;
- 工厂方法的参数;
- 在对象的实例通过构造函数或者工厂方法返回后,注入其属性;
然后,Spring Container在创建bean时便注入这些依赖。
使用DI原则,代码更简洁,当对象具有依赖关系时,解耦更有效。
对象不需要查找依赖项,也不知道依赖项的位置或类。因此,您的类变得更容易测试,特别是当它依赖于接口或抽象基类时。
DI主要有两种形式:
- 基于构造函数;
- 基于Setter函数——基于setter的DI是在调用无参构造函数或无参静态工厂方法来实例化bean之后,在bean上调用setter方法来完成的。
对于这两种方式,有个最佳实践:
对强制依赖项使用构造函数,为可选依赖项使用setter方法或配置方法( configuration methods)。注意,在setter方法上使用@Required注释可以使属性成为必需的依赖项。
Spring Team通常提倡构造函数注入,因为它允许您将应用程序组件实现为不可变对象,并确保所需的依赖项不是空的。此外,通过构造函数注入的组件总是以完全初始化后的状态返回给客户端的(调用)代码。
顺便提一句,构造函数参数过多是一种糟糕的代码,这意味着类可能承担了太多的责任。对此应该进行重构,以更好分离所关注的点。
而Setter注入应该主要用于可选的依赖项,这些依赖项可以在类中分配合理的默认值。不然的话,在任何使用该依赖项的地方都需要进行非空检查。Setter注入的一个优势是setter方法使该类的对象能够在以后重新进行配置或重新注入。
特殊情况下,例如,如果第三方类不公开任何setter方法,则构造函数注入可能是惟一可用的DI形式。
IOC Container是完成DI的步骤:
- 首先,使用描述所有bean的配置元数据来创建和初始化ApplicationContext。配置元数据可以由XML、Java代码或注释指定。
- 然后,对于每个bean,其依赖项以属性、构造函数参数或静态工厂方法的参数的形式表示(如果您使用它而不是普通的构造函数)。当bean实际被创建时,这些依赖项将提供给bean。
- 接着,每个属性或构造函数参数都是要设置的值的实际定义,或者是对容器中另一个bean的引用。
- 最后,每个作为值的属性或构造函数参数都从其指定的格式转换为该属性或构造函数参数的实际类型。默认情况下,Spring可以将以字符串格式提供的值转换为所有内置类型,例如int、long、string、boolean等等。
事实上,Spring的Container在被创建时就会验证每个bean的配置,尽管bean的属性直到bean在被创建时才被设置。
但是singleton-scoped和pre-instantiated (默认情况)的bean都是在Container创建时被创建。否在,bean都是在被请求时才被创建。
一个bean的创建可能会引起一系列的bean被创建,因为它的依赖项,以及依赖项的依赖项都会被创建和分配。
引申:关于循环依赖
如果主要使用构造函数注入,则可能会产生一个无法解决的“循环依赖”的场景。
例如:Class A requires an instance of class B through constructor injection, and class B requires an instance of class A through constructor injection. If you configure beans for classes A and B to be injected into each other, the Spring IoC container detects this circular reference at runtime, and throws a BeanCurrentlyInCreationException
.
一种解决方案是:让其中的一些类使用setter方法进行依赖注入。或者,全都只使用setter方法。换句话说,尽管不建议这样做,但可以使用setter注入解决循环依赖的问题。
在创建bean时,Spring会尽可能晚地去设置其属性以及解决其依赖项。这意味着,在你请求一个对象时,如果在创建对象或解决其依赖项时出现问题,正确加载的Spring容器可能稍晚才会生成异常。这也是为什么ApplicationContext的实现类默认会预先初始化单例的bean。在这些bean被实际请求前,花费一些前期时间和内存来创建他们,可以保证在ApplicationContext创建时发现一些配置问题。
当然你也可以覆盖这种默认的行为,让singleton bean晚点被初始化。
在不存在依赖循坏的情况下,如果Bean A依赖于Bean B,那么Spring会在完全初始化Bean B后,再进行将其注入A中。
五、Bean Scopes
Spring框架支持六个bean的作用域,而在web相关的ApplicaitonContext中,只支持其中四个。
还可以创建自定义scope。
以下是六种作用域,后四个是web相关:
singleton---一个bean的定义,在一个IOC容器中只会有它的一个实例。这意味着每次对这个容器中这个bean的请求,返回的都是同一个实例。
prototype---一个bean的定义,在一个IOC容器中可以有多个实例。每次的请求,都会引起同一个bean的新的实例的创建。
request--- bean作用于HTTP request的生命周期,而每个HTTP request都拥有它自己的实例bean,这个bean的声明周期也随同request的生命周期。只在web相关的Spring ApplicationContext中才有意义。
session--- bean作用于HTTP session的生命周期,每个HTTP session都有自己的实例bean。
application--- Scopes a single bean definition to the lifecycle of a ServletContext.
websocket---Scopes a single bean definition to the lifecycle of a WebSocket。
对于singleton和prototype的使用,有一个原则:应该对所有“有状态”的bean使用prototype作用域,对“无状态”的bean使用单例作用域。
数据访问对象(DAO)通常不配置为原型,因为典型的DAO不包含任何会话状态。
与其他作用域不同,Spring并不管理prototype bean的完整生命周期。
容器在初始化并配置好一个prototype对象后,就把它交给客户端,此后不在有这个prototype对象实例的任何记录。因此,尽管对所有对象都调用初始化生命周期回调方法,而不管作用域如何,但在prototype 的情况下,配置的销毁生命周期回调方法不会被调用。而客户端代码必须自己清理prototype实例对象并且释放它所占用的资源。Spring也为此提供了一个专用的容器,来释放被这些prototype-scoped bean所占用的资源(try using a custom bean post-processor, which holds a reference to beans that need to be cleaned up)。
某种程度上来说,Spring容器在prototype bean中的角色只是是Java new操作符的替代品。此后的所有生命周期管理都必须由客户端来处理。
Spring IOC Container的更多相关文章
- Spring IoC Container and Spring Bean Example Tutorial
Spring Framework is built on the Inversion of Control (IOC) principle. Dependency injection is the t ...
- Spring IoC Container源码分析(二)-bean初始化流程
准备 Person实例 @Data public class Person { private String name; private int age; } xml bean配置 <?xml ...
- Spring IOC Container原理解析
Spring Framework 之 IOC IOC.DI基础概念 关于IOC和DI大家都不陌生,我们直接上martin fowler的原文,里面已经有DI的例子和spring的使用示例 <In ...
- Spring-Framework-官方文档阅读(一)Spring IoC Container
通读Spring IoC容器官方文档,对IoC容器有一个大致的了解. 环境 JDK1.8 Spring Framework Version :4.3.18.RELEASE 容器概述 接口org.spr ...
- Spring学习笔记之三----基于Annotation的Spring IOC配置
使用Annotation 来创建Bean有两种方式 在配置类中创建bean(配置类是指标注为@Configuration的类),在配置类中每一个创建bean的方法都应该标注为@Bean,可以在@Bea ...
- 【Spring】初始化Spring IoC容器(非Web应用),并获取Bean
参考文章 Introduction to the Spring IoC container and beans BeanFactory 和ApplicationContext(Bean工厂和应用上下文 ...
- Spring IOC小记
1. What IOC (Inversion Of Control,控制反转)与DI(Dependency Injecion,依赖注入) 用于对象间解耦,如在以前若对象A依赖B则需要在A中负责B的创建 ...
- 一分钟玩转 Spring IoC
前言 「上一篇文章」我们对 Spring 有了初步的认识,而 Spring 全家桶中几乎所有组件都是依赖于 IoC 的. 刚开始听到 IoC,会觉得特别高大上,但其实掰开了很简单. 跟着我的脚步,一文 ...
- 一分钟玩转 Spring IoC!
前言 「上一篇文章」我们对 Spring 有了初步的认识,而 Spring 全家桶中几乎所有组件都是依赖于 IoC 的. 刚开始听到 IoC,会觉得特别高大上,但其实掰开了很简单. 跟着我的脚步,一文 ...
随机推荐
- linux调用库的方式
linux调用库的方式有三种:1.静态链接库2.动态链接库3.动态加载库 其中1,2都是在编程时直接调用,在链接时加参数-l进行链接,运行时自动调用第三种需要在编程时使用dlopen等函数来获取库里面 ...
- jmeter-移动端接口测试中遇到的问题,http与https
解决:将请求默认值的http改成https
- 《你不知道的JavaScript(上)》笔记——作用域是什么
Javascript是一门编译语言,它不是提前编译的, 编译结果也不能在分布式系统中进行移植. 在传统编译语言的流程中, 程序中的一段源代码在执行之前会经历三个步骤, 统称为"编译" ...
- Vue UI组件库
1. iView UI组件库 iView官网:https://www.iviewui.com/ 2.Vux UI组件库 Vux官网:https://vux.li/ 3.Element UI组件库 ...
- API网关的用处
API网关我的分析中会用到以下三种场景. Open API. 企业需要将自身数据.能力等作为开发平台向外开放,通常会以rest的方式向外提供,最好的例子就是淘宝开放平台.腾讯公司的QQ开发平台.微信开 ...
- PAT 甲级 1012 The Best Rank (25 分)(结构体排序)
题意: 为了评估我们第一年的CS专业学生的表现,我们只考虑他们的三个课程的成绩:C - C编程语言,M - 数学(微积分或线性代数)和E - 英语.同时,我们鼓励学生强调自己的最优秀队伍 - 也就是说 ...
- springMVC配置文件学习
spring配置文件分为dao层,web层,service层,三层配置 这三层配置中, dao层对应数据库的配置:进行数据库相关和model实体类的配置 web层对应controller包中配置:设置 ...
- Hadoop 部署之 ZooKeeper (二)
目录 一.Zookeeper功能简介 二.ZooKeeper基本概念 1.集群角色 三.ZooKeeper 的安装 1.下载安装(在datanode节点安装) 2.配置ZooKeeper环境变量 3. ...
- 在 Laravel 中使用 MongoDB
可参考:https://blog.csdn.net/weixin_38682852/article/details/80840678 环境准备 安装 MongoDB 安装 PHP-MongoDB 扩 ...
- systemctl daemon-reload
systemctl daemon-reload: 重新加载某个服务的配置文件,如果新安装了一个服务,归属于 systemctl 管理,要是新服务的服务程序配置文件生效,需重新加载. init 和 sy ...