您现在的位置是:亿华云 > IT科技
详解Spring 如何创建 Bean 对象?
亿华云2025-10-09 01:27:25【IT科技】1人已围观
简介前情回顾前文「Spring 如何从 IoC 容器中获取对象?」从整体上分析了如何从 Spring IoC 容器获取一个 bean 对象。该逻辑由 AbstractBeanFactory#doGetBe
前情回顾前文「Spring 如何从 IoC 容器中获取对象?详解象」从整体上分析了如何从 Spring IoC 容器获取一个 bean 对象。该逻辑由 AbstractBeanFactory#doGetBean 方法实现,何创主要流程如下:

本文进一步深入细节,详解象主要分析如何创建 singleton(单例)类型的何创对象。
如何创建单例对象?详解象
从流程图可以看出,当获取一个 bean 对象时,何创Spring 会首先尝试从缓存中获取单例对象。详解象
值得注意是何创的:
只有对象是单例的场景,即 scope 为 singleton 时才会缓存对象。详解象 这里其实涉及到了所谓的何创「三级缓存」,为了更容易理解三级缓存,详解象本文先研究这个 bean 对象是何创什么时候放入缓存的,后面再研究三级缓存。详解象既然能取,何创必然有地方把 bean 对象存入了缓存,详解象那缓存中的数据是从哪里来的呢?
下面主要分析单例对象是如何创建、并放入缓存中的。
该逻辑在 AbstractBeanFactory#doGetBean 方法中,主要代码如下(保留了创建单例 bean 对象的代码,其他部分暂时忽略):
public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory { // ... protected <T> T doGetBean( String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException { String beanName = transformedBeanName(name); Object bean; // 从缓存中获取单例 bean 对象 Object sharedInstance = getSingleton(beanName); // 缓存中不存在 bean 对象 else { // ... try { // 获取 BeanDefinition RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); // 获取依赖的云服务器提供商 bean 对象 // 若创建一个 bean 对象时依赖其他对象,则先创建被依赖对象 // ... // 创建 scope 为 singleton(单例)的对象 if (mbd.isSingleton()) { sharedInstance = getSingleton(beanName, () -> { try { return createBean(beanName, mbd, args); } catch (BeansException ex) { // ... } }); // 处理 FactoryBean 的场景 bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); } // 创建 scope 为 prototype 的对象 else if (mbd.isPrototype()) { // ... } // 创建其他类型对象 else { // ... } } catch (BeansException ex) { // ... } } // 类型检查 return (T) bean; } }其实就是这个 DefaultSingletonBeanRegistry#getSingleton 方法,代码如下:
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry { // 单例 bean 对象缓存(beanName, bean) private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256); public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) { Assert.notNull(beanName, "Bean name must not be null"); synchronized (this.singletonObjects) { // 先从缓存中获取 bean 对象 Object singletonObject = this.singletonObjects.get(beanName); // 缓存中不存在时再去创建 if (singletonObject == null) { // ... // 创建单例对象前 beforeSingletonCreation(beanName); boolean newSingleton = false; boolean recordSuppressedExceptions = (this.suppressedExceptions == null); if (recordSuppressedExceptions) { this.suppressedExceptions = new LinkedHashSet<>(); } try { // 创建单例对象 singletonObject = singletonFactory.getObject(); newSingleton = true; } // catch ... finally { if (recordSuppressedExceptions) { this.suppressedExceptions = null; } // 创建单例对象后 afterSingletonCreation(beanName); } if (newSingleton) { // 将对象添加到缓存 addSingleton(beanName, singletonObject); } } // 缓存中有的话直接返回 return singletonObject; } } }getSingleton 方法会先从缓存 singletonObjects(其实就是一个 Map)中获取 bean 对象,如果缓存有就直接返回,否则再去创建。创建成功后,会把该对象存入缓存。
创建的逻辑在哪呢?
看代码是通过 ObjectFactory#getObject 方法来创建的,ObjectFactory 是一个函数式接口:
@FunctionalInterface public interface ObjectFactory<T> { T getObject() throws BeansException; }这个方法的实现是什么呢?退回上一层,即 getBean 方法,看这里:
sharedInstance = getSingleton(beanName, () -> { try { // 创建 bean 对象 return createBean(beanName, mbd, args); } catch (BeansException ex) { // ... } });这里用到了 Lambda 表达式,将如下表达式作为参数:
() -> { try { // 创建 bean 对象 return createBean(beanName, mbd, args); } catch (BeansException ex) { // ... } }创建 bean 对象的逻辑就在这个 createBean 方法中,它在 AbstractAutowireCapableBeanFactory 类中:
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory implements AutowireCapableBeanFactory { @Override protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException { RootBeanDefinition mbdToUse = mbd; Class<?> resolvedClass = resolveBeanClass(mbd, beanName); if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) { mbdToUse = new RootBeanDefinition(mbd); mbdToUse.setBeanClass(resolvedClass); } // Prepare method overrides. try { mbdToUse.prepareMethodOverrides(); } // catch ... try { // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance. // 这里可能返回代理对象 Object bean = resolveBeforeInstantiation(beanName, mbdToUse); if (bean != null) { return bean; } } // catch ... try { // 创建 bean 对象 Object beanInstance = doCreateBean(beanName, mbdToUse, args); if (logger.isTraceEnabled()) { logger.trace("Finished creating instance of bean " + beanName + ""); } return beanInstance; } // catch ... } } 值得注意的是,resolveBeforeInstantiation 方法其实是跟 AOP 实现相关的,可能在这里生成代理对象就返回了。由于现在主要分析 IoC 的网站模板流程,因此这里暂时略过,有兴趣的朋友们可以自行研究。这里继续沿着主线逻辑走。
创建 bean 对象是在 doCreateBean 方法中实现的,如下:
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory implements AutowireCapableBeanFactory { protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException { // Instantiate the bean. // 1. 实例化 bean BeanWrapper instanceWrapper = null; if (mbd.isSingleton()) { instanceWrapper = this.factoryBeanInstanceCache.remove(beanName); } if (instanceWrapper == null) { instanceWrapper = createBeanInstance(beanName, mbd, args); } Object bean = instanceWrapper.getWrappedInstance(); Class<?> beanType = instanceWrapper.getWrappedClass(); if (beanType != NullBean.class) { mbd.resolvedTargetType = beanType; } // Allow post-processors to modify the merged bean definition. synchronized (mbd.postProcessingLock) { if (!mbd.postProcessed) { try { applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName); } // catch ... mbd.postProcessed = true; } } boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName)); if (earlySingletonExposure) { addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)); } // Initialize the bean instance. Object exposedObject = bean; try { // 2. 填充属性 populateBean(beanName, mbd, instanceWrapper); // 3. 初始化 exposedObject = initializeBean(beanName, exposedObject, mbd); } // catch ... if (earlySingletonExposure) { Object earlySingletonReference = getSingleton(beanName, false); if (earlySingletonReference != null) { if (exposedObject == bean) { exposedObject = earlySingletonReference; } else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) { String[] dependentBeans = getDependentBeans(beanName); Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length); for (String dependentBean : dependentBeans) { if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) { actualDependentBeans.add(dependentBean); } } // ... } } } // Register bean as disposable. try { registerDisposableBeanIfNecessary(beanName, bean, mbd); } // catch ... return exposedObject; } } 注意:Instantiate 和 Initialize 虽然看起来有点像,但它俩不是一回事,前者是“实例化”,后者是“初始化”。这个方法看起来有点长,但最主要的事情只有三件:
创建 bean 对象:createBeanInstance 方法 填充属性:populateBean 方法 初始化 bean:initializeBean 方法这几个方法内部其实都有一大堆堆堆堆堆……的代码,再对照一下前面给出的整体流程图 :
就是这样。
本文在前文整体分析的基础上又进一步细化,先到这里吧,后面再继续分析~
小结
如何从 Spring IoC 容器中获取 bean 对象?前文对此进行了整体流程的分析。
本文在前文的基础上又进一步细化,主要从整体上探讨了 Spring 如何创建单例的 bean 对象,整体上分为三个步骤:
创建 bean 对象。 填充 bean 属性 初始化 bean 对象至于这三个步骤具体又做了什么,b2b信息网且听下回分解。
很赞哦!(9683)
相关文章
- 互联网其实拼的也是人脉,域名投资也是一个时效性很强的东西,一个不起眼的消息就会引起整个域名投资市场的动荡,因此拓宽自己的人脉圈,完善自己的信息获取渠道,让自己能够掌握更为多样化的信息,这样才更有助于自己的域名投资。
- 掌控你的追随者与粉丝,尽在.ART
- 域名的组成部分有哪些?
- 国内域名拼音加英文还是全拼好?
- 尽量不要在域名中出现特殊字符,这样的域名很容易导致访问者输入错误,同时给人留下不专业的印象,降低网站的可信度,并流失大量潜在客户。
- Redis 6.X Sentinel 哨兵集群搭建
- 聊聊 Wasm 扩展 Envoy 使用详解
- 企业搭建官网的域名去哪里找?
- 因为域名解析需要同步到DNS根服务器,而DNS根服务器会不定时刷,只有DNS根服务器刷新后域名才能正常访问,新增解析一般会在10分钟左右生效,最长不会超过24小时,修改解析时间会稍微延长。
- 域名无法注册怎么办?