spring的bean加载过程
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");
User user = (User) applicationContext.getBean("user");
spring的bean加载是从getBean方法开始的。
一、从缓存中获取bean
Object sharedInstance = getSingleton(beanName);
protected Object getSingleton(String beanName, boolean allowEarlyReference);
该方法首先尝试从singletonObjects里面获取实例,如果获取不到再从earlySingletonObjects里获取,如果还获取不到,再尝试从sigletonFactories里面获取beanName对应的ObjectFactory,然后调用这个ObjectFactory的getObject来创建bean,并放到earlySingletonObjects,并将sigletonFactories的对应bean缓存删除掉。
存储bean的map解释:
/** Cache of singleton objects: bean name to bean instance. */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
singletonObjects 用于保存BeanName和创建bean实例之间的关系。
/** Cache of early singleton objects: bean name to bean instance. */
private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);
earlySingletonObjects 提前曝光的单例对象缓存,用于解决循环依赖
/** Cache of singleton factories: bean name to ObjectFactory. */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
singletonFactories 用于保存BeanName和创建bean的工厂之间的关系。
内部方法解释:
public boolean isSingletonCurrentlyInCreation(String beanName);
判断当前bean是否处于创建中,即正在初始化,但是尚未完成初始化。
allowEarlyReference参数:是否允许从singletonFactories缓存中通过getObject方法拿到bean对象。
二、从bean实例中获取对象
beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd);
if (!(beanInstance instanceof FactoryBean)) {
return beanInstance;
}
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
在getBean
方法中获取到的bean,只是原始状态的bean,不一定是我们想要的。需要调用getObjectForBeanInstance
进行处理。getObjectForBeanInstance
对非factoryBean不做处理,直接返回,将解析bean的工作委托给getObjectFromFactoryBean
。
if (factory.isSingleton() && containsSingleton(beanName))
Object object = doGetObjectFromFactoryBean(factory, beanName);
getObjectFromFactoryBean
方法主要内容是如果是单例则从缓存中获取,缓存没有则从factoryBean中获取。如果不是单例,则直接去从factoryBean中获取bean.获取bean的操作又委托给了doGetObjectFromFactoryBean
,最终调用 object = factory.getObject();
获取bean.
三、获取bean流程
从spring容器中获取单例时有两种情况:缓存中存在和缓存中不存在。在上面缓存中不存在单例bean时,是通过getSingleton的重载方法来实现bean的加载的。
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
});
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory);
主要过程为:
1,再次尝试从缓存中取出bean
Object singletonObject = this.singletonObjects.get(beanName);
2, 若没有加载,则记录beanName的正在加载状态
beforeSingletonCreation(beanName);
protected void beforeSingletonCreation(String beanName) {
if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
}
/** Names of beans that are currently in creation. */
private final Set<String> singletonsCurrentlyInCreation =
Collections.newSetFromMap(new ConcurrentHashMap<>(16));
3, 通过传入ObjectFactory创建bean
singletonObject = singletonFactory.getObject();
4,当bean加载结束后需要移除缓存中正在加载状态
protected void afterSingletonCreation(String beanName) {
if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) {
throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation");
}
}
5,将结果记录至缓存并删除加载bean所记录的各种辅助状态
addSingleton(beanName, singletonObject);
this.singletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
四、创建bean
return createBean(beanName, mbd, args);
太长,另起一篇。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了