(4)Bean的加载

Spring动态加载Bean的4种实现方式与最佳实践 条件化Bean加载是Spring框架的核心特性之一,通过运行时决策机制实现组件的动态注册。其技术原理基于环境抽象(Environment)和BeanDefinition注册机制,开发者可以通过@Conditional等条件注解实现灵活配置。这种机制在微服务架构中尤为重要,既能实现环境隔离(如dev/test/prod配置分离),又能支持功能开关等动态特性。典型的应用场景包括多支付渠道切换、不同数据库驱动加载等模块化需求。结合Spring Boot的自动配置机制,开发人员可以进一步实现starter级别的动态 阅读详情

这里写图片描述

这里写图片描述

protected <T> T doGetBean(
        final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
        throws BeansException {

    final String beanName = transformedBeanName(name);
    Object bean;

    // Eagerly check singleton cache for manually registered singletons.
    /*检查缓存中或者实例工厂中是否有对应的实例
     *因为在创建单例bean的时候会存在依赖注入的情况,为了避免循环引用
     *Spring创建bean的原则是不等bean创建完成就会将创建bean的ObjectFactory提早曝光
     *即将ObjectFactory加入到缓存之中,一旦下一个bean创建的时候需要依赖上一个bean则直接
     *使用beanFactory 
    */
    Object sharedInstance = getSingleton(beanName);
    if (sharedInstance != null && args == null) {
        if (logger.isDebugEnabled()) {
            if (isSingletonCurrentlyInCreation(beanName)) {
                logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
                        "' that is not fully initialized yet - a consequence of a circular reference");
            }
            else {
                logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
            }
        }
        bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
    }

    else {
        // Fail if we're already creating this bean instance:
        // We're assumably within a circular reference.
        // 原型类型的bean是不允许循环依赖的,所以Exception
        if (isPrototypeCurrentlyInCreation(beanName)) {
            throw new BeanCurrentlyInCreationException(beanName);
        }

        // Check if bean definition exists in this factory.
        BeanFactory parentBeanFactory = getParentBeanFactory();
        if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
            // Not found -> check parent.
            String nameToLookup = originalBeanName(name);
            if (args != null) {
                // Delegation to parent with explicit args.
                return (T) parentBeanFactory.getBean(nameToLookup, args);
            }
            else {
                // No args -> delegate to standard getBean method.
                return parentBeanFactory.getBean(nameToLookup, requiredType);
            }
        }
        //如果不仅仅是做类型检查,则需要进行记录
        if (!typeCheckOnly) {
            markBeanAsCreated(beanName);
        }

        try {
            final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
            checkMergedBeanDefinition(mbd, beanName, args);

            // Guarantee initialization of beans that the current bean depends on.
            String[] dependsOn = mbd.getDependsOn();
            if (dependsOn != null) {
                for (String dependsOnBean : dependsOn) {
                    if (isDependent(beanName, dependsOnBean)) {
                        throw new BeanCreationException("Circular depends-on relationship between '" +
                                beanName + "' and '" + dependsOnBean + "'");
                    }
                    registerDependentBean(dependsOnBean, beanName);
                    getBean(dependsOnBean);
                }
            }

            // Create bean instance.
            if (mbd.isSingleton()) {
                sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
                    @Override
                    public Object getObject() throws BeansException {
                        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;
                        }
                    }
                });
                bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
            }

            else if (mbd.isPrototype()) {
                // It's a prototype -> create a new instance.
                Object prototypeInstance = null;
                try {
                    beforePrototypeCreation(beanName);
                    prototypeInstance = createBean(beanName, mbd, args);
                }
                finally {
                    afterPrototypeCreation(beanName);
                }
                bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
            }

            else {
                String scopeName = mbd.getScope();
                final Scope scope = this.scopes.get(scopeName);
                if (scope == null) {
                    throw new IllegalStateException("No Scope registered for scope '" + scopeName + "'");
                }
                try {
                    Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() {
                        @Override
                        public Object getObject() throws BeansException {
                            beforePrototypeCreation(beanName);
                            try {
                                return createBean(beanName, mbd, args);
                            }
                            finally {
                                afterPrototypeCreation(beanName);
                            }
                        }
                    });
                    bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
                }
                catch (IllegalStateException ex) {
                    throw new BeanCreationException(beanName,
                    "Scope '" + scopeName + "' is not active for the current thread; " +
                    "consider defining a scoped proxy for this bean if you intend to refer to it 
                    from a singleton",
                            ex);
                }
            }
        }
        catch (BeansException ex) {
            cleanupAfterBeanCreationFailure(beanName);
            throw ex;
        }
    }

    // Check if required type matches the type of the actual bean instance.
    if (requiredType != null && bean != null && !requiredType.isAssignableFrom(bean.getClass())) {
        try {
            return getTypeConverter().convertIfNecessary(bean, requiredType);
        }
        catch (TypeMismatchException ex) {
            if (logger.isDebugEnabled()) {
                logger.debug("Failed to convert bean '" + name + "' to required type [" +
                        ClassUtils.getQualifiedName(requiredType) + "]", ex);
            }
            throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
        }
    }
    return (T) bean;
}

实际的doGetBean过程很复杂,拆成步骤来分析
1.转换对应的beanName

这里写图片描述

因为这里传入的参数可能是别名,也可能是FactoryBean,所以要进行一系列的解析,解析的内容包括:
去除FactoryBean的修饰符,也就是如果name=”&aa”,那么会首先去除&而使name=”aa”
取置顶alias所表示的最终beanName,例如别名A指向名称为B的bean则返回B,如果A指向B,B又指向C则返回C

这里写图片描述

2.尝试从缓存中加载bean

这里写图片描述

这里写图片描述

这里写图片描述

默认allowEarlyReference是设置为true的
这个的作用是为了处理singleton bean的依赖注入的情况,在创建依赖的时候为了避免循环依赖,Spring创建bean的原则是不等bean创建完成就会将创建的ObjectFactory提早曝光加入到缓存中,一旦下一个bean创建时需要依赖上一个bean,则直接使用ObjectFactory

注:定义bean的时候是可以指定scope的,默认是单例

先说一下各个缓存的作用:

这里写图片描述

singletonObjects:
用于保存BeanName和创建bean实例之间的关系,bean name -> bean instance
singletonFactories:
用于保存BeanName和创建bean的工厂之间的关系,bean name -> ObjectFactory
earlySingletonObjects:
也是保存BeanName和创建bean实例之间的关系,与SingletonObjects的不同之处在于,当一个实例bean被放到这里面后,那么当bean还在创建的过程中,就可以通过getBean方法获取到了,其目的是用来检测循环引用
registeredSingletons:
用来保存当前所有已注册的bean

在缓存之中没有拿到bean
这里写图片描述

3.Bean的实例化,如果从缓存中得到了bean的原始状态,则需要对bean进行实例化。

强调:缓存中记录的只是最原始的bean状态,并不一定是我们最终想要的bean。
切记

这里写图片描述

在getBean方法中,getObjectForBeanInstance是个高频率使用的方法,无论是从缓存中获得bean还是根据不同的scope策略加载bean。总之,得到bean的实例后要做的第一件事就是调用这个方法来检测一下正确性。
这里写图片描述

这里写图片描述

这里写图片描述

这里为什么会有&作为前缀?通常使用的FactoryBean也是直接用BeanName来获取的。
当使用&作为前缀的时候表示用户想要的是直接获取FactoryBean工厂实例而不是FactoryBean.getObject()对应的实例。

处理FactoryBean

这里写图片描述

先是从缓存中拿FactoryBean,如果拿不到真正的获取FactoryBean的逻辑委托给getObjectFromFactoryBean
这里写图片描述

这里还是就判定一下是否单例,是单例需要保证全局唯一,并且使用缓存。实际的创建逻辑在doGetObjectFromFactoryBean之中
这里写图片描述
终于看到了factory.getObject()
不过在调用factory.getObject()获取bean之后并没有直接返回bean,还有下面一部分:
这里写图片描述
调用的是AbstractAutowireCapableBeanFactory之中的postProcessObjectFromFactoryBean()
这里写图片描述
这里写图片描述
这里是调用了后处理器,这里可以了解Spring获取bean的规则中的一条:
尽可能保证所有bean初始化后都会调用注册的BeanPostProcessor的postProcessAfterInitialization方法进行处理,在实际的开发工程中大可以针对此特性设计自己的业务逻辑。

同时说一下applyBeanPostProcessorsBeforeInitialization
这里写图片描述
暂时还没有看到调用的时机

到此全部是从缓存中寻找是否有singletonbean,已经从FactoryBean之中获取bean

如果都失败了,那么进入else
这里写图片描述
只有在单例情况下才会尝试解决循环依赖,如果A依赖B,B依赖A,那么造成循环依赖,引起BeanCurrentlyInCreationException

美团2017运维笔试真题解析:Linux、网络排查与故障定位能力 在互联网技术快速迭代的今天,Linux系统管理与网络协议原理依然是运维工程师的立身之本。无论是处理TCP连接中的TIME_WAIT状态,还是分析HTTP状态码背后的链路问题,系统化排查思路都远比死记命令更重要。故障定位能力直接决定线上业务的稳定性,而监控体系与自动化脚本设计则帮助团队从被动响应走向主动预防。从系统启动流程到内核参数调优,从CPU飙高定位到磁盘inode耗尽,这些看似基础的技能正是应对复杂生产环境的基石。本文以美团2017年校招运维笔试真题为切入点,结合真实工程实践,梳理高频考点背后的能力模型 阅读详情

相关推荐

实例化Spring bean的两种工厂方法

通过实例工厂方法和静态工厂方法实例化spring bean的例子。

spring 常见错误

1.log如下 org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: Unnamed bean definition specifies neither 'class' nor 'parent' nor 'factory-bean' - can't gene

xiaocai9999的专栏 1734

基于TL431与光耦的电压反馈环路优化设计实战

本文深入探讨了基于TL431与光耦的电压反馈环路优化设计实战。文章从理解这对“黄金搭档”的工作原理入手,详细拆解了电压采样电阻网络、偏置电路、光耦工作点设置以及动态补偿网络的设计心法与计算步骤。重点分享了如何通过RC补偿网络调试,确保环路在各种负载下稳定可靠,并提供了关键的实战避坑指南,帮助工程师解决电源设计中常见的振荡、噪声及可靠性问题。

nginx7reverse的博客 776

详解Spring的GetBean方法

Spring容器提供了五种获取Bean的方式,可以根据beanName获取Bean,也可以根据classType来获取Bean,所有根据beanName来获取Bean的方式,底层都会通过调用下面的doGetBean()来获取Bean对象 protected <T> T doGetBean( String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly

sermonlizhi的博客 9507

NCCL分布式训练中ibv_reg_mr_iova2内存分配失败的3种解决方案(附详细排查流程)

本文深入探讨了NCCL分布式训练中ibv_reg_mr_iova2内存分配失败的3种解决方案,包括快速临时修复、标准系统配置和PAM模块根治方案。详细分析了错误原因,提供了完整的排查流程和性能优化建议,帮助开发者高效解决RDMA网络环境下的内存锁定问题。

nut55的博客 624

保姆级教程:从 TLE 数据源获取到 Cesium 卫星轨迹可视化全流程(含常见报错排查)

本文提供从TLE数据源获取到Cesium卫星轨迹可视化的全流程保姆级教程,涵盖数据预处理、satellite.js计算、Cesium集成及性能优化等关键步骤,并针对常见报错提供详细排查方案,帮助开发者高效实现卫星轨迹可视化。

weixin_29002595的博客 295

关于Spring的注入问题

其中一个方法参考于:https://blog.youkuaiyun.com/ziany/article/details/78845433 最近在开发的时候,遇见了一个问题,Spring的配置文件和Struts2的配置文件无法注入Service,虽然已知是因为线程无法注入Service,但是一直没有很好的解决方法,虽然用过几种常见的用法,但并不能有效的使用,当今天无意间看见这个博文的时候,试了一下,果然好使,...

DocLong的博客 331

深入探究贝叶斯网络(Bayesian Network):从基础原理到实际应用

贝叶斯网络,也称为信念网络或有向无环图模型,是一种概率图模型。它使用有向无环图(DAG)来表示随机变量之间的条件依赖关系。每个节点代表一个随机变量,边表示变量之间的条件依赖关系。贝叶斯网络作为一种强大的工具,通过结合概率论和图论,为复杂系统建模和推理提供了有效手段。无论是在医学诊断、故障检测还是自然语言处理等领域,它都展示了巨大的潜力。然而,其计算复杂度高、结构学习困难等挑战也需要我们在实际应用中不断优化算法和技术。希望通过本文,你能对贝叶斯网络有更深入的理解,并能够在实际项目中灵活应用这一强大工具。

qq_28791753的博客 5966

SpringloC容器的依赖注入源码解析(3)—— doGetBean之剩余逻辑

文章目录 doGetBean源码: protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType, @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException { // 先将方法传入的name转换成容器真实的beanName // 之前可以通过三种形式获取beanN

如切如磋,如琢如磨 914

[QMT量化交易小白入门]-四十九、中小盘策略是否还有未来,市值再平衡策略,年化收益率124%

该策略旨在通过定期再平衡持仓,保持投资组合中股票数量恒定(),并优先持有市值较小的股票。具体来说,策略每两天(period = 2)进行一次再平衡,根据当前市值对持仓进行调整,以实现微盘股的投资目标。中小市值策略对资金量要求有限制,资金量太大由于流动性不足,滑点可能较大,资金量太小,可能不能达到10-20只持仓,来分散风险,10-100w可能是比较理想的,后续可以根据波动率动态调仓,或波动率大于一定值时触发再平衡加入ROE或其他财务指标,或者研发投入强度大的专精特新企业,进行组合优化。

木头大左的博客 1183

基于MATLAB的最大重叠离散小波变换(MODWT)算法详解

最大重叠离散小波变换(Maximal Overlap Discrete Wavelet Transform, MODWT)是DWT的重要改进形式,由Percival和Walden等人在20世纪90年代系统提出并完善。MODWT通过消除下采样操作,采用样本平移不变的分解方式,解决了DWT的多个固有缺陷。MODWT的核心创新在于取消下采样环节。与DWT每级分解后对滤波输出进行二分下采样不同,MODWT在每一级都使用相同的滤波器,但通过插入零值的方式调整滤波器系数,保持每级系数数量与原始信号相同。

qq_42212808的博客 115

从Spring源码角度看@Autowired(上篇)

从源码角度看@Autowired @Autowired注解的源码 @Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE}) @Retention(RetentionPolicy.RUNTIME) @Docu...

Hershey's Blog 653

Amazon Skills:51个AI技能赋能亚马逊运营,从选品到广告全链路分析

在电商运营领域,数据分析和自动化工具正成为提升效率的关键。其核心原理在于将专业经验转化为结构化指令,使AI能够执行标准化流程。这种技术价值体现在降低专业门槛、提升决策效率,尤其适用于亚马逊这类数据驱动的电商平台。通过将选品、关键词研究、FBA费用计算、PPC广告优化等运营框架编码为可执行指令,AI助手能够模拟专家思维进行市场分析。Amazon Skills项目正是这一理念的实践,它提供51个覆盖运营全链路的技能模块,让卖家在自然对话环境中获得专业分析支持,实现从市场研究到利润核算的自动化工作流。

weixin_27134143的博客 1292

Spring源码5.4Bean的加载 从Bean的实例中获取对象

Rush6666的博客 264

手把手教你学Simulink——基于Simulink的无感FOC(滑模观测器+PLL)实战

本文详细介绍了基于Simulink的无感FOC(滑模观测器+PLL)实现方法。主要内容包括:1)SMO+PLL原理精讲,阐述滑模观测器核心思想和PLL的作用;2)系统架构全景图展示;3)Simulink建模全流程,从基础FOC框架到SMO和PLL模块的实现;4)关键参数整定指南和工程实践要点;5)仿真结果分析及常见问题解决方案。该方法可有效替代机械传感器,降低成本并提高可靠性,适用于空调压缩机、电动汽车水泵等工业场景。文章还提供了详细的调试建议和动手实践指导。

MHD0815的博客 83

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

Spring源码解析——4、bean的加载

Spring源码解析——4、bean的加载 bean的加载1、FactoryBean的使用2、缓存中获取单例bean3、从bean的实例中获取对象4、获取单例bean5、准备创建bean5.1 处理oveirrde属性5.2 实例化的前置处理6、循环依赖6.1 什么是循环依赖6.2 Spring如何解决循环依赖7、创建bean7.1创建bean的实例 bean的加载 对于加载bean的功能,s...

大智的博客 665

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

Spring——4. Bean的加载(一)

文章目录1. 转换对应的beanName1.1 FactoryBean1.1.1 FactoryBean的作用1.1.2 FactoryBean的使用1.2 转换beanName2. 缓存中获取单例bean3. 从bean实例中获取真正的bean对象4. 从头开始bean实例的加载4.1 原型模式的依赖检查4.2 检测parentBeanFactory4.3 标记 alreadyCreated4.4 转换GenericBeanDefinition为RootBeanDefinition4.5 寻找依赖4.6

m0_52325992的博客 385

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

【Spring Boot】4.条件化Bean 根据配置文件加载对应Bean

根据配置文件只加载指定的Bean,条件化Bean 近期在工作中遇到实际问题:在不同的环境中,需要加载不同的工具类。这个就可以使用到Spring的条件化Bean。 话不多说,直接上代码。 例如,当前对于IService接口: public interface IService { void test(); } 有两个不同的实现类: public class AwsServiceImpl implements IService{ @Override public void test.

卤小蛋学编程 5355

Spring 4.x 源码系列2-bean加载

一、前沿 在上节文章 ApplicationContext refresh 刷新 中我们学习了Spring启动是如何将所有的bean实例化并加载的,其中我们只分析到了Spring将bean的定义转换为 BeanDefinition,并注册到 BeanFactory 中,后续的bean的实例化和初始化(bean的加载)我们没有讲解,我们将 bean 的实例化和初始化称之为 bean 的加载,本文将...

大龙的博客 370

spring框架4 - bean加载

** 3:如果存在parentBeanFactory 并且 配置中也没有beanName的配置信息,则尝试从parentBeanFactory中获取实例 *//** 4:将GenericBeanDefinition转换为RootBeanDefinition,如果是子Bean,则与父类的相关属性进行合并 *//** 9:检查需要的类型是否符合bean的实际类型,如果不同,则对其进行类型转换 *//** 6:创建bean的单例实例对象 *//** 2:缓存中不存在实例,则采取自主创建实例对象 */

QiAn的博客 428

4.IOC容器源码解读—Bean定义加载过程解读

BeanDefinition,bean定义的接口行为描述。BeanDefinition接口中定义了Bean定义的相关行为,我们从中可看到很多熟悉的项。如对里面的信息项不熟,请查看代码的注释。同时请对比看xml配置的dtd或xsd,在beans.jar中org.springframework.beans.factory.xml 包下:spring-beans.dtd 或 spring-beans.xsd。/***/......Bean定义的信息最终注册到哪里去了呢?

RubyWinner的博客 986

Spring4.1.4 bean的加载与赋值

既然是学习,那么我们就从spring的基础开始。对于本篇了解了的朋友可以提提意见,不了解的朋友就顺带着写写代码,感受一下实现的快感。 定义javabean 这个bean里面我们定义了name、age和hobby三个属性。 并定义了四个构造方法,在下面讲解的时候会一一说到。  package com.itxxz.user.bean;      /**   * 用

zcf396720的专栏 402

Spring源码解析笔记4——bean的加载

首先先说一下FactoryBean。Spring中的两种bean,一种是普通的Bean,另外一种是FactoryBean,FactoryBean是Spring留给使用者自己定义实例化bean的逻辑的接口。 FactoryBean接口源码: package org.springframework.beans.factory; public interface FactoryBean {

xyh的博客 388

【老王最佳实践-4】一招解决bean的优先加载问题

有时,我们会碰到一个 bean 在使用时,却没有被 spring 容器加载。例如下面的 PropertiesHelper 类,我们在另一个类 FooService 中使用了静态方法来获取配置值,却报了空指针。碰到这种问题,通常的做法就是在 FooService 加载前,让 PropertiesHelper 优先加载,比如使用 @DependOn 或者 在 FooService 中 @Autowired 自动注入 PropertiesHelper。

老王的专栏 549

Sprng源码4--bean的加载

#########Spring的类加载机制

weixin_43689953的博客 192

spring4 xml文件更新重新加载bean的奇葩问题

问题是这样的 开发环境:win7 + tomcat7 + jdk1.7 + spring4.5 我用xml配置了应用要用到的一些参数信息bean,tomcat启动之后,我修改了xml文件里的参数信息,然后用以下方法重新加载bean Resource resource = new ClassPathResource(ymall.xml); BeanFactory bf = new XmlBe

草雅空间 1063
上一篇: java虚拟机的基本结构
下一篇: GC的算法与种类
sicofield
博客等级 码龄18年 169粉丝 169原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值