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,会觉得特别高大上,但其实掰开了很简单. 跟着我的脚步,一文 ...
随机推荐
- python 简单了解一下 描述器
1.描述器是什么? 在Python中描述器也被称为描述符, 1)描述器实际上是任何新式类(新式类是继承自 type 或者 object 的类),这种类至少实现了3个特殊的方法__get__, __se ...
- x86 linux下如何交叉编译?
答: 需要首先指定两个环境变量CROSS_COMPILE和ARCH 如交叉编译arm64的程序: export CROSS_COMPILE="aarch64-linux-gnu-" ...
- Android中利用jsoup解析html页面
学习jsoup :jsoup学习网站 Android 中使用: 添加依赖 implementation 'org.jsoup:jsoup:1.10.1' 直接上代码: package com.load ...
- [hibernate]log4jdbc日志输出完整SQL语句
1.在maven引入: <dependency> <groupId>log4j</groupId> <artifactId>log4j</arti ...
- RabbitMQ运转流程
生产者发送消息的过程 生产者连接到RabbitMQ Broker(相当于是一个RabbitMQ服务器),建立一个连接(Connection),开启一个信道(Channel). 生产者声明一个交换器(E ...
- jenkins:多个job时怎么按照一定顺序执行构建
一.安装Jenkins多项目构建插件(我已安装):Multijob 二.新建Multijob Project任务 三.配置
- EasyNetQ使用(五)【基于主题的路由,控制队列名称】
RabbitMQ有一个很酷的功能,基于主题的路由,这个功能允许订阅者基于多个条件去过滤消息.一个主题是由点号分隔的单词列表,随消息一同发布.例如:“stock.usd.nyse” 或 “book.uk ...
- .Netcore 2.0 Ocelot Api网关教程(7)- 限流
本文介绍Ocelot中的限流,限流允许Api网关控制一段时间内特定api的总访问次数.限流的使用非常简单,只需要添加配置即可. 1.添加限流 修改 configuration.json 配置文件,对 ...
- 三小时攻克 Kubernetes!
我保证本文是最详尽的 Kubernetes 技术文档,从我在后台排版了这么漫长的时间就能看出来.废话不多说——牢牢占据容器技术统治地位的 Kubernetes,其重要性想必不言而喻. 以下为译文: 为 ...
- Unity爬坑记录-Sprite 相关功能Editor、打包器等无法使用
找了好久的问题,同一个Unity,但是不同项目,一个没问题,一个出现上面情况.