Spring IOC原理

概述

  • IOC 的作用:解耦、单例缓存、Bean生命周期管理、父子容器
  • IOC 工作要经历2个过程:启动预加载BeanDefination、实例化对象且缓存单例,传统BeanFactory的实现类是懒加载(loadClass时再实例化bean),而web容器实现是预加载(启动和实例化一起进行)。但是BeanDefination都是预加载的。

IOC的作用

  1. 解耦:
  • 实现了类与类依赖关系的解耦,大家都注册在IOC容器当中,并不直接强耦合。有多种注入类的方式:xml配置、@Component 注解、@import、@Configuration等等
  • 实现了类的依赖关系和代码的解耦:把类的依赖关系,可以不通过修改代码,而是通过修改 xml然后容器来实现,这给非开发人员带来了很多便利
  1. 单例缓存:基于容器注册,就可以灵活缓存,避免内存空间的浪费,提升创建bean的速度。如果通过new的方式,就无法做到。
  2. 预处理:对Bean生成进行干预(init、构造函数、属性赋值、对象销毁)等过程进行干预
  3. 父子容器:MVC的实现就是很好的例子,既有一定的隔离性,又可以复用父容器的类

IOC容器启动和创建Bean逻辑

image

总体逻辑:IOC容器启动时,把所有配置过的Bean都全部各自生成一个BeanDefinition,并存储到BeanDefinitionRegistry的beanDefinitionMap中;用户在通过BeanFactory接口的实现类去getBean的时候,会从beanDefinitionMap中获取到这个bean的BeanDefinition,然后通过反射生成一个Bean,默认单例的话,还会把这个实例化的bean存储在singletonObjects中,下次再getBean的时候就直接从singletonObjects中返回

  1. 在IOC容器启动的时候,去扫描指定的application.xml,从而获取到需要注册的Bean的信息,不管你后期会不会用到这个Bean,所有扫到的Bean都会各自封装成一个BeanDefinition
  2. 因为Spring默认是懒加载,只有程序getBean的时候才会真正的实例化这个Bean,而实例化Bean的时候需要知道这个Bean的BeanDefinition(因为BeanDefinition里面有这个Bean的所有相关信息),所以需要BeanDefinitionRegistry这个BeanDefinition的管理器,来判断这个Bean是否已经注册生成了BeanDefinition,否则只有遍历所有创建过的BeanDefinition,才能知道你要get的这个Bean是否已经生成BeanDefinition
  3. BeanDefinitionRegistry接口主要负责管理所有注册过的BeanDefinition,比如增删改查功能,他的实现类需要2个工具成员变量:beanDefinitionMap、singletonObjects(都是ConcurrentHashMap结构)
  4. beanDefinitionMap负责缓存所有注册过的BeanDefinition;singletonObjects为单例类的缓存器,每个通过BeanDefinitionRegistry创建出来的bean,都缓存在singletonObjects里面,除非是多例
  5. 而BeanFactory接口是面向用户的,实际上他只是一个触发器,用户调用getBean方法,会先去beanDefinitionMap查找这个Bean是否已经生成了BeanDefinition,没有就报错,有就根据BeanDefinition来反射创建一个Bean,因为默认是单例的,创建完之后就缓存在singletonObjects里面

Spring getBean流程的细节

  1. 缓存查询:查询singletonObjects中是否有缓存
  2. 实例化DependsOn的类:查询类A是否是dependsOn的类,有的话,需要先实例化dependsOn的类
  3. 创建一个空的实体类:读取BeanDefinition信息,获取空的构造函数,通过反射创建一个所有filed为null的实体类(这样在堆中就有一个引用了)然后把这个Bean保存到singletonFactories中(以参数的形式 把bean存到factory里面)
  4. 然后遍历该类A的依赖属性,一一赋值,如果属性值依赖的是某一个具体的类B的时候,就必须先实例化B类
  5. 最后把创建好的Bean缓存在singletonObjects中,再返回给调用者

Spring 生命周期管理

  1. 实例化Bean执行顺序:调用构造函数、属性值的set方法、init方法(如果配置了的话)、destory方法
  2. 类通过实现特定的接口,来实现在某个过程中进行干预
  3. Spring 也支持配置容器级别的 干预类,注入到IOC当中后,所有的类在创建过程中,都会收到干预

普通Java Bean的生命周期

比如main方法里面,new User()这个操作,就会从class文件里面加载一个User对象到JVM里。

JavaBean的生命周期:类加载、连接、验证、准备、初始化

  • 其中包括类静态成员变量的初始化为默认值
  • 静态成员变量设置为设置值或者静态代码块的执行
  • 调用构造函数

另外Java 加载Bean的触发条件:

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