6.7 SpringBean的生命周期
6.7.1 bean的实例化
在配置好bean后,Spring取出beanDefinition查看它是否是单例bean,是否需要延迟加载等,这些都是bean语句里的那些配置信息,完成后通过反射将bean实例化。
6.7.2 bean的初始化
经过上面步骤的的bean只是一个半成品,还需要再加工。这个阶段很重要,主要完成像上面提到的Spring后处理方法,完成相关属性的注入,执行自定义初始化方法或者InitializingBean方法等。
-
bean属性注入
-
实现Aware接口
-
执行postProcessBeforeInitialization方法
-
执行InitializingBean方法
-
执行自定义init方法
-
执行postProcessAfterInitialization方法
下面几步在上次演示过了,就说下bean属性配置和实现Aware接口。
bean属性注入:包括普通属性(int,String等),单向对象属性,双向对象属性。
所谓单向对象属性,简单来说,就比如Service里引用了UserDao。
<bean id="Service" class="com.demo.impl.ServiceImpl" > <property name="userDao" ref="userDao"></property> </bean> <bean id="userDao" class="com.demo.impl.UserDaoImpl"></bean>
这里就会有个时机问题:当Service实例化后,开始注入UserDao,但此时UserDao还没有实例化。所以,Service就会停下来,等UserDao实例化后才开始注入。
当然,如果是放在前面的话,就不存在这种情况了。
而双向对象属性,不仅Service里引用了UserDao,而且UserDao里也引用了Service。
<bean id="Service" class="com.demo.impl.ServiceImpl" > <property name="userDao" ref="userDao"></property> </bean> <bean id="userDao" class="com.demo.impl.UserDaoImpl"> <property name="service" ref="Service"></property> </bean>
多个实体之间相互依赖并形成闭环,我们称之为“依赖闭环”,也叫做“循环引用”。这样会发生什么呢?来看:
当我们从getBean(“userService”)进入,先实例化Service,这个时候,内存空间里就有Service的位置了。随后Service开始初始化,如果容器里有userDao,那好说,直接拿来注入,但如果没有,则要先去实例化userDao,同样的道理,userDao实例化需要注入Service,但此时Service还没有初始化,userDao在单例池中就找不到Service,于是它也停下来等Service装进去,它等,它也等,就这样一直陷在死循环里。
那怎么办?
三级缓存的提出解决了这个问题。它的思想就是当需要注入时,不再在单例池中找,而是单独存另外一个Map中,先引用过来,后续需要什么再自己补充。
在底层源码中,Spring提供了三种Map:
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry { private static final int SUPPRESSED_EXCEPTIONS_LIMIT = 100; //一级缓存,存完整的bean对象,即单例池Map private final Map<String, Object> singletonObjects = new ConcurrentHashMap(256); //二级缓存,存半成品bean,但是这个bean是已经被其他实体引用了的 private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap(16); //三级缓存,存半成品bean,未被其他实体引用 private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap(16);
结合上面的图来讲,当Service实例化后,将它存入三级缓存中,需要注入userDao时,先完成userDao的实例,userDao存在三级缓存中,userDao然后需要注入Service,那userDao就可以从三级缓存中找到Service,拿过来后,Service就从三级缓存中删除了,随后存在二级缓存中。而userDao后来在完成它的初始化,实现bean对象的完整过程,删除三级缓存,存进一级缓存(单例池)中。然后回溯到Service的userDao注入,它就可以直接从单例池中找到userDao,完成它的初始化等过程,最后删除二级缓存,进入一级缓存。
流程图如下:(主要看缓存)
先是各自完成了实例化:
随后Service被userDao引用后,进入二级:
userDao完成bean对象的创建,进入单例池:
Service完成bean对象的创建,进入单例池:
6.7.3 bean的完成
经过上面这些步骤,bean才真正成为一个对象,然后装填在单例池中。
总体来看下。
标签:实例,缓存,userDao,Service,SpringBean,bean,生命周期,单例 From: https://blog.csdn.net/Ggjvhsjsj/article/details/143301349