这篇文章从代码的角度过一遍三级缓存,三级缓存,其实就是bean的创建过程。这里只介绍单例模式,原型模式有机会再单独介绍
创建bean的入口getBean()方法
这里getBean()方法,默认指的是DefaultListableBeanFactory的getBean()方法。这里我们说的三级缓存,其实是我们自己的叫法,人家源码压根就没有"缓存"这样的命名,三级缓存其实是bean创建时所需要经过的是三个容器
- Map<String, Object> singletonObjects 单例对象池(一级缓存)
- 已经创建完成的Bean对象,会被存到这里
- Map<String, Object> earlySingletonObjects 早期单例对象池(二级缓存)
- 从singletonFactories拿出来的还未完成创建的Bean,会存到这里
- Map<String, ObjectFactory<?>> singletonFactories 单例工厂(三级缓存)
- 创建bean过程中,执行属性填充的时候,发现依赖其他的对象,就会把当前创建的对象,暴露到singletonFactories
为了防止下面创建的过程大家听得一头雾水,这里先明确两个概念"实例化"和"初始化",这里会简单粗暴的把基础的概念告诉你,但是它具体是个什么东西,请自行看源码
- 实例化
- new ClassA() 这种创建了一个对象的,就称之为实例化。(Spring中实例化,用的是反射,但是大同小异,反正这个对象被构建出来了)
- 初始化
- ClassA a = new ClassA(); 这里是实例化
- a.setName()
- a.init()
- 这种给你的实例化对象赋值和执行初始化方法的过程,叫做初始化(当然你也可以把赋值和执行初始化方法分开,根据你看源码的理解自行理解)
- 一个对象初始化完,其实就是执行完init方法,已经没有什么需要填充或者执行delete
我们要说的是单例模式,所以这些bean,只能创建第一次。如果存在多个类依赖同一个对象,或者出现了循环依赖,要怎么处理呢?Spring就通过上面的三个容器,去解决这些问题。
getSingleton()获取单例对象
获取单例对象。很明显,我们的bean是一个单例,所以我们需要获取这个单例。那么这个单例,是不能被重复创建的,如果我获取这个单例的时候,这个单例没创建,或者在创建中怎么办?带着问题我们去看Spring是怎么实现的
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// Quick check for existing instance without full singleton lock
// 先去单例池里找,看下有没有创建好的单例bean可以直接拿
Object singletonObject = this.singletonObjects.get(beanName);
// 没有创建好的,而且这个bean正在创建中(isSingletonCurrentlyInCreation(beanName))
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
// 去早期的单例池里获取单例bean
singletonObject = this.earlySingletonObjects.get(beanName);
// 还是没有,allowEarlyReference(是否允许早期暴露)
if (singletonObject == null && allowEarlyReference) {
synchronized (this.singletonObjects) {
// Consistent creation of early reference within full singleton lock、
// 再去单例池拿一次(双重检查锁,确认上锁后单例池有没有对应的单例对象)
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
// 去早期单例池拿
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null) {
// 去单例工厂拿
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
// 执行getObjec()方法,拿到对象
singletonObject = singletonFactory.getObject();
// 放入早期单例池
this.earlySingletonObjects.put(beanName, singletonObject);
// 从单例工厂删除
this.singletonFactories.remove(beanName);
}
}
}
}
}
}
// 返回拿到的单例对象(可以为null)
return singletonObject;
}
这里的目的就是为了从单例池里获取到一个对象,这里说下singletonFactory这里为什么调用了getObject()方法
@FunctionalInterface
public interface ObjectFactory<T> {
T getObject() throws BeansException;
}
因为ObjectFactory是一个lambda表达式,getObject()后返回的,才是真实的对象
可以看到,我们只是去拿了一下单例bean,如果拿不到,那就要进入创建bean的流程
另一个getSingleton(String beanName, ObjectFactory<?> singletonFactory)
上面的那个getSingleton()的作用是拿一个单例bean,有就返回单例,没有就返回null,这个方法,是拿一个单例,没有就创建一个单例返回 这里传入了一个ObjectFactory,其实也就是我们单例工厂(三级缓存存的值)
先看一下入口方法:
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
getSingleton(beanName, () -> {
try {
// 内部lambda表达式,直接调用的createBean()方法
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
destroySingleton(beanName);
throw ex;
}
});
}
那么真正的创建bean的方法,就在createBean()里面了
createBean()
try {
// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
// 内部调用InstantiationAwareBeanPostProcessor,让你可以这个地方,返回一个对象(或者代理对象)。
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
}
// 没有返回代理兑现的时候,走的真实的创建方法
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
下面贴出主干代码,中间会有省略,需要的自行查看源码。
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
// Instantiate the bean.
// 实例化bean
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
// 这里是看下哟没有实例化的缓存
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
// 这里是实例化对象的地方,返回的是已经实例化好的对象的包装类
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
// 从包装类中拿出真实的对象
Object bean = instanceWrapper.getWrappedInstance();
}
// 判断是否需要提前暴露,需要的话,加入单例工厂
// Eagerly cache singletons to be able to resolve circular references
// even when triggered by lifecycle interfaces like BeanFactoryAware.
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isTraceEnabled()) {
logger.trace("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
// 加入单例工厂(也就是我们说的三级缓存)
// 这里可以看到,这里其实是把一个lambda表达式放入了map,当你需要用的时候,就会去执行getEarlyBeanReference
// 当你从SingletonFactory拿到了lambda表达式执行完以后,就会放入earlySingletonObjects.put,这时返回的,也可能是个代理对象
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// Initialize the bean instance.
// 初始化bean
Object exposedObject = bean;
try {
// 填充属性
// 填充属性的时候,会判断属性是否有对象,有的话就走getBean()方法,递归去创建bean
populateBean(beanName, mbd, instanceWrapper);
// 执行初始化方法,内部会调用BeanPostProcessor的实现类(代理对象可以在这里被创建)
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
// Register bean as disposable.
// 执行完以后
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
// 直接返回当时传入的bean,或者走SmartInstantiationAwareBeanPostProcessor的实现方法,返回一个新的bean
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
// 就是这里,可以返回一个代理对象
for (SmartInstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().smartInstantiationAware) {
exposedObject = bp.getEarlyBeanReference(exposedObject, beanName);
}
}
return exposedObject;
}
细心的学可能注意到了(也可能没注意到),上面有三个钩子可以让你创建代理对象。
- 实现InstantiationAwareBeanPostProcessor.class,让你不走doCreateBean,直接返回一个对象(或者代理对象)
- 约等于强制替换,创建bean的时候,从InstantiationAwareBeanPostProcessor.class拿到了bean就直接返回这个bean,不继续走下面的流程了
- 实现SmartInstantiationAwareBeanPostProcessor.class,让你在从singletonFatory中拿bean对象的时候,返回一个对象(或者代理对象)
- 解决创建过程中,代理对象的问题
- 在有依赖关系的bean创建中,提前暴露当前bean,然后在需要注入到其他类的时候,执行一次SmartInstantiationAwareBeanPostProcessor.class,把返回的值放入earlySingletonObjects
- 这里的做法目的是,如果有代理对象,在单例模式下,不会重复去创建这个代理对象,也保证被依赖的Bean可以直接拿到代理对象
- 实现BeanPostProcessor.class,让你在initializeBean()内,执行invokeInitMethods()前后,可以返回一个对象(或者代理对象)
- 这里就是正常初始化好bean以后,看下需不需要返回代理对象或者替换掉当前的bean
这里Spring给你同时照顾到了几种情况
- 假如一个项目中,我需要替换掉一个bean,自己自定义的bean,那么我可以在InstantiationAwareBeanPostProcessor.class的时候,直接给它替换成自己需要的bean返回,不走它后面的创建流程
- 当有依赖关系时(BCD依赖A),那么被依赖的bean(BCD),通过earlySingletonObjects可以直接拿到A的代理对象
- 当需要给初始化好的bean做增强时,可以通过实现BeanPostProcessor.class,对原本完整的bean 做增强。
最后通过public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory)这个方法创建的新bean,会加入singletonObjects和registeredSingletons,从singletonFactories和earlySingletonObjects删除
protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
this.singletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
总结
整个bean的创建流程到这里就差不多了,这里没有贴太多细节出来,因为整个bean的创建过程是非常复杂的。这里就说说创建一个新的单例bean如果经过三级缓存,是怎么一个流程
- 首先,创建bean的时候,会先去三级缓存中拿,三级缓存中拿不到就会去创建
- 拿的顺序是,一级、二级、三级
- 三级拿到的是一个lambda表达式,执行lambda表达式的默认方法,会返回bean或者bean的代理对象,这里返回的值,会放入二级缓存,然后从三级缓存删除,避免重复去执行lambda表达式,返回新的对象,毕竟单例bean就应该只被创建一次
- 然后这里做一个勘误,虽然拿的方式是一级、二级、三级,但是从二级拿的bean不会直接放到一级,bean只有完全按创建完,才会放入一级,然后删掉二级和三级,没有从二级拿到一级的操作
- 创建的过程中,如果当前的bean有依赖,就会提前把自己暴露到三级缓存,然后去创建依赖的bean
- 如果依赖的bean里面还有依赖,就会继续暴露当前的bean,继续创建依赖的bean,就这样一直递归创建
- 如果有循环依赖A->B,B->A这种情况
- 由于A依赖B,A会先暴露到三级,然后去创建B,B创建时发现依赖A,也会暴露到三级,然后去拿A
- B通过执行A的提前暴露lambda表达式,可以拿到A或者A的代理对象,然后把A或A的代理放到二级缓存
- B拿到A以后,继续创建流程,B创建完以后,把自己放入一级缓存和registeredSingletons,删除二级、三级缓存,然后返回给A
- A在创建完B以后,继续执行创建流程,A创建完以后,把自己放入一级缓存和registeredSingletons,删除二级、三级缓存
- 这样就是一个完整创建过程了