【JAVA面试】Spring Bean

提示:文章先作为初版,等后续时间充足后,补充更深的内容


Spring Bean

一、作用域

singleton

使用该属性定义Bean时,IOC容器仅创建一个Bean实例,IOC容器每次返回的是同一个Bean实例。

prototype

使用该属性定义Bean时,IOC容器可以创建多个Bean实例,每次返回的都是一个新的实例。

request

该属性仅对HTTP请求产生作用,使用该属性定义Bean时,每次HTTP请求都会创建一个新的Bean,适用于WebApplicationContext环境。

session

该属性仅用于HTTP Session,同一个Session共享一个Bean实例。不同Session使用不同的实例。

global-session

该属性仅用于HTTP Session,同session作用域不同的是,所有的Session共享一个Bean实例。

二、简述bean的生命周期

在这里插入图片描述

1、实例化(Instantiation)bean对象

​ 通过反射的方式进行对象的创建,此时的创建只是在堆空间中申请空间,属性都是默认值

2、设置对象属性(Populate)

​ 给对象中的属性进行值的设置工作,populateBean()循环依赖的问题(三级缓存)

3、检查Aware相关接口并设置相关依赖

​ 如果对象中需要引用容器内部的对象,那么需要调用aware接口的子类方法来进行统一的设置,invokeAwareMethod(完成BeanName,BeanClassLoader对象的属性设置)

4、BeanPostProcessor的前置处理

​ 在Bean实例初始化之前,对Bean进行额外的处理。这个阶段可以进行一些自定义的操作,例如对Bean进行代理、修改属性等。对生成的bean对象进行前置的处理工作(ApplicationContextPostProcessor)

5、初始化方法(Initialization)

​ 如果Bean实现了InitializingBean接口,Spring会调用其定义的**afterPropertiesSet()**方法进行初始化。同时,如果在Bean的配置中配置了init-method,该方法也会在此阶段被调用。如下6

6、检查是否配置有自定义的init-method方法

​ 如果当前bean对象定义了初始化方法,那么在此处调用初始化方法

7、BeanPostProcessor后置处理

​ 对生成的bean对象进行后置的处理工作,调用BeanPostProcessor的后置处理方法:spring的aop就是在此处实现的,注册Destuction相关的回调接口:钩子函数

8、注册必要的Destruction相关回调接口

​ 为了方便对象的销毁,在此处调用注销的回调接口,方便对象进行销毁操作

9、获取并使用bean对象

​ 通过容器来获取对象并进行使用,可以通过getBean的方法进行对象的获取

接下来是销毁流程

10、销毁方法(Destruction)
如果Bean实现了DisposableBean接口,Spring会在容器关闭时调用其定义的destroy()方法进行销毁。同时,如果在Bean的配置中配置了destroy-method,该方法也会在此阶段被调用。

循环依赖问题

循环依赖问题三级缓存,提前暴露对象,AOP
A依赖B同时B又依赖A,A对象有B的属性,B对象有A的属性,Bean的创建过程,实例化,初始化。①创建A对象,实例化A对象,此时A对象中的b属性为空②从容器中查找B对象,如果找到了,直接赋值不存在循环依赖问题,找不到直接创建B对象③实例化B对象,此时B对象中的a属性为空,填充属性a,④从容器中查找A对象,找不到,直接创建。这是形成闭环的原因。这时候的A对象是存在的,A对象不是一个完整的状态,只完成了实例化但是未完成初始化。如果在程序的调用过程中,拥有了某个对象的引用,能否在后期给他完成赋值操作,可以优先吧非完整状态的对象先赋值,等待后续操作来完成赋值,相当于提前暴露某个不完整的对象引用。解决这种问题的核心在于实例化和初始化分开操作,这也是解决循环依赖问题的关键,当所有对象都完成了实例化和初始化操作之后,还要吧完整的对象放到容器中,此时在容器中存在对象的几个状态:完成实例化但未完成初始化,完整状态。因为都在容器中,所以要使用不同的map结构来存储。所以就有了一级和二级缓存。如果一级缓存中有了,那么二级缓存就不会存在同名对象,因为他们的查找顺序是1,2,3这样的方式来查找的。一级缓存中放完整对象,二级缓存放非完整对象。
为什么需要三级缓存,三级缓存村的Value类型是ObjectFactory是一个函数式的接口,存在的意义是保证在整个容器的运行过程中同名的bean对象只能有一个,一个对象需要被代理,或者说需要生成代理对象的时候,要优先生成一个普通对象,普通对象和代理对象不能同时出现在容器中,因此当一个对象需要被代理的时候,就要使用代理对象覆盖之前的普通对象。在实际的回调过程中,是没有办法确定什么时候对象被调用,所以就要求当某个对象被调用的时候,优先判断此对象是否需要被代理,类似一种回调机制的实现,因此传入lambda表达式来执行对象鹅覆盖过程getEarlyBeanReference()。因此所有的Bean对象在创建的过程中都要优先放到三级缓存中,在后续的使用过程中,需要被代理就返回代理对象,不需要被代理就返回普通对象。

缓存放置的时间和删除的时间:
三级缓存:createBeanInsteance之后
二级缓存:第一次从三级缓存确定对象是代理对象还是普通对象的时候,同时删除三级缓存。
一级缓存:生成完整对象之后放到一级缓存,删除二三级缓存


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值