createBean方法详解

2023-11-09

前言:

  createBean是创建Bean的主要方法

   该方法位于:AbstractBeanFactory的doGetBean方法中的createBean调用、

createBean方法流程图:

 createBean源码解析:

protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
            throws BeanCreationException {

        if (logger.isTraceEnabled()) {
            logger.trace("Creating instance of bean '" + beanName + "'");
        }
        RootBeanDefinition mbdToUse = mbd;//该参数是从AbstractBeanFactory的doGetBean传递过来的父子容器合并BeanDefinition

        // Make sure bean class is actually resolved at this point, and
        // clone the bean definition in case of a dynamically resolved Class
        // which cannot be stored in the shared merged bean definition.
        //判断需要创建的Bean是否可以实例化,即是否可以通过当前的类加载器加载
        Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
        if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
            //克隆一份BeanDefinition,用来设置上加载出来的class对象
            //之所以后续用该副本操作,是因为不希望将解析的class绑定到缓存里的BeanDefinition
            //因为class有可能是每次都需要动态解析出来的
            mbdToUse = new RootBeanDefinition(mbd);
            mbdToUse.setBeanClass(resolvedClass);
        }

        // Prepare method overrides.
        //校验和准备Bean中的方法覆盖
        try {
            mbdToUse.prepareMethodOverrides();//如果是0个则抛异常,如果是1个也就没有重载的必要
        }
        catch (BeanDefinitionValidationException ex) {
            throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
                    beanName, "Validation of method overrides failed", ex);
        }

        try {
            // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
            //如果Bean配置了初始化前和初始化后的处理器,则试图返回一个需要创建Bean的代理对象
            //resolveBeforeInstantiation只是针对有自定义的targetsource,
            //因为自定义的targetsource不是spring的bena,那么肯定不需要进行后续的一系列的实例化,初始化。
            //所以可以在resolveBeforeInstantiation直接进行proxy
            Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
            if (bean != null) {
                //如果这里有处理器在bean创建的之前 给出了代理bean,则无需执行后续的逻辑,
                // 直接返回用户给出的bean
                return bean;
            }
        }
        catch (Throwable ex) {
            throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
                    "BeanPostProcessor before instantiation of bean failed", ex);
        }

        try {
            //创建Bean的入口
            Object beanInstance = doCreateBean(beanName, mbdToUse, args);
            if (logger.isTraceEnabled()) {
                logger.trace("Finished creating instance of bean '" + beanName + "'");
            }
            return beanInstance;
        }
        catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
            // A previously detected exception with proper bean creation context already,
            // or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry.
            throw ex;
        }
        catch (Throwable ex) {
            throw new BeanCreationException(
                    mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
        }
    }
createBean源码解析

createBean方法大致流程:

  (1)判断需要创建的Bean是否可以实例化,即是否可以通过当前的类加载器加载(如果可以,克隆一份BeanDefinition)  

    (2)用BeanDefinition副本调用prepareMethodOverrides()方法,进行校验Bean和准备Bean中的方法覆盖(处理方法覆盖)

  (3)⭐处理Bean配置的初始化前后的处理器(前置:该方法里头会调用所有的Bean处理器,如果处理器中有调换了bean的,则返回bean,如果没有则返回null)

  (4)⭐调用doCreateBean()方法,该方法是创建Bean的入口

doCreateBean方法流程图:

 

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
            throws BeanCreationException {

        // Instantiate the bean.
        //bean实例包装类
        BeanWrapper instanceWrapper = null;
        if (mbd.isSingleton()) {
            //从未完成创建的包装Bean缓存中清理并获取相关中的包装Bean实例,毕竟是单例,只能存一份
            instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
        }
        if (instanceWrapper == null) {
            //创建bean的时候,这里创建bean的实例有三种方法
            //1.工厂方法创建
            //2.构造方法的方式注入
            //3.无参构造方法注入
            instanceWrapper = createBeanInstance(beanName, mbd, args);//********
        }
        //获取被包装的Bean,后续对bean的改动相对于对Wrapper的改动,反之依然
        final Object bean = instanceWrapper.getWrappedInstance();
        //获取实例化对象的类型
        Class<?> beanType = instanceWrapper.getWrappedClass();
        if (beanType != NullBean.class) {
            mbd.resolvedTargetType = beanType;
        }

        // Allow post-processors to modify the merged bean definition.
        //调用BeanDefinition属性合并完成后的BeanPostProcessor后置处理器
        synchronized (mbd.postProcessingLock) {
            if (!mbd.postProcessed) {
                try {
                    //@Autowired、@Value标记的属性在这里获取
                    //应用合并后的BeanDefinition后置处理器
                    applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
                }
                catch (Throwable ex) {
                    throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                            "Post-processing of merged bean definition failed", ex);
                }
                mbd.postProcessed = true;
            }
        }

        // Eagerly cache singletons to be able to resolve circular references
        // even when triggered by lifecycle interfaces like BeanFactoryAware.
        //向容器中缓存单例模式的Bean对象,以防循环引用
        //判断是否是早期引用的bean,如果是,则允许其提前暴露引用
        // 这里判断的逻辑主要有三个∶
        //1.是否为单例
        //2 是否允许循环引用
        //3.是否是在创建中的bean
        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");
            }
            //这里是一个匿名内部类,为了防止循环引用,尽早持有对象的引用
            //将还没完全配置好的bean存入到三级缓存中供其他bean使用(暴露引用)
            addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
            //这里的getEarlyBeanReference()方法,并不是在此调用,而是声明好了方法
            //具体的调用在Spring的AbstractBeanFactory的doGetBean的第三行调用
            // DefaultSingletonBeanRegistry类的getSingleton方法中,调用
            // singletonFactory.getObject()(单例工厂的getObject方法返回实例对象)
        }

        // Initialize the bean instance.
        //Bean对象的初始化,依赖注入在此触发
        //这个exposedObject在初始化完成之后返回作为依赖注入完成后的Bean
        Object exposedObject = bean;//暴露的对象
        try {
            //填充bean实例的属性
            populateBean(beanName, mbd, instanceWrapper);

            //初始化bean,过程如下:
            //1.判断是否实现了BeanNameAware,BeanClassLoaderAware,BeanFactoryAware方法,
            //如果有,则设置相关的属性
            //2.调用bean初始化前的前置(BeanPostProcessor)操作
            //3.执行初始化的方法
            //如果有InitializingBean,则调用afterPropertiesSet
            //如果有InitMethod,则调用初始方法
            //4.调用bean初始化的后置(BeanPostProcessor)操作
            exposedObject = initializeBean(beanName, exposedObject, mbd);
        }
        catch (Throwable ex) {
            if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
                throw (BeanCreationException) ex;
            }
            else {
                throw new BeanCreationException(
                        mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
            }
        }

        //若允许循环依赖,则解决相关的循环依赖
        //earlySingletonExposure是前面代码判断出来的是否:暴露引用bean
        if (earlySingletonExposure) {
            //获取指定名称的已注册的单例模式Bean对象
            //这里的getSingleton()从三层缓存中依次去获取,由于
            //先前我们已经将对象存入到三级缓存中,所有这里在三级缓存获取得到
            //然后缓存中的对象被放到了二级缓存中,三级中移除了
            Object earlySingletonReference = getSingleton(beanName, false);//
            if (earlySingletonReference != null) {
                //如果经过initializeBean执行后返回的bean还是同一个(不是代理对象实例,即没有被增强)
                if (exposedObject == bean) {
                    //确保根据名称获取到的
                    exposedObject = earlySingletonReference;
                }
                //如果上面的if没通过,则表明引用的bean和注入的bean不一致,则需要看看依赖于此Bean的先前是否已经
                //allowRawInjectionDespiteWrapping标注是否允许此Bean的原始类型被注入到其他Bean里面,
                //即使自己最终会被包装(代理)
                //dependentBeanMap记录着每个依赖于此Bean的Bean实例集合
                //当发生循环引用时不允许新创建实例对象
                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);
                        }
                    }
                    //因为Bean创建后其所依赖的Bean一定是已经创建的
                    //actualDependentBeans不为空则表示当前Bean创建后其依赖的Bean却没有全部创建完,也就是说
                    if (!actualDependentBeans.isEmpty()) {
                        throw new BeanCurrentlyInCreationException(beanName,
                                "Bean with name '" + beanName + "' has been injected into other beans [" +
                                StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
                                "] in its raw version as part of a circular reference, but has eventually been " +
                                "wrapped. This means that said other beans do not use the final version of the " +
                                "bean. This is often the result of over-eager type matching - consider using " +
                                "'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
                    }
                }
            }
        }
doCreateBean源码解析

doCreateBean方法大致流程:

  (1)判断BeanDefinition是不是单例的,如果是单例的,从未完成创建的包装Bean缓存中清理并获取相关中的包装Bean实例,毕竟是单例,只能存一份

  (2)判断第一步中获到的包装Bean实例如果是空的,调用createBeanInstance()方法创建bean,这里创建bean的实例有三种方法

    (1)尝试获取BeanDefinition里面的Class对象 

    (2)检查是否有权通过反射创建private的Class

    (3)如果bean使用的是java自带的函数式接口Supplier(工厂方法),则调用里头的get创建返回bean实例

    (4)如果BeanDefinition里面有定义Spring的工厂方法如(factory-method),则调用factory-method创建返回实例 

    (5)查询BeanDefinition中有没有缓存好的构造函数或者工厂方法,有则调用创建返回实例

    (6)判断是否使用(带惨构造函数装配)如果都不是最终调用无参构造函数创建返回实例  

  (3)获取被包装的Bean,后续对bean的改动相对于对Wrapper的改动,反之依然,获取实例化对象的类型并放入BeanDefinition中

  (4)对BeanDefinition的后置处理器上锁操作,判断BeanDefinition没有使用后置处理器,后调用applyMergedBeanDefinitionPostProcessors()方法应用合并后的BeanDefinition后置处

    理器(@Autowired、@Value标记的属性在这里获取) applyMergedBeanDefinitionPostProcessors内部跟绝大部分后置处理器一样采用了责任链模式,循环遍历所有后置处理器,

    IF实现了MergedBeanDefinitionPostProcessor接口的 后置处理器便调用postProcessMergedBeanDefinition方法这里我们重点关注:AutowiredAnnotationBeanPostProcessor.postProcessMergedBeanDefinition()

      (1)进入AutowiredAnnotationBeanPostProcessor类,首先我们可以看到该类的无参构造方法中对@Autowired、@Value注解添加到了该类的成员变量里。

      (2)我们查看postProcessMergedBeanDefinition()方法

        (A)首先第一行调用了findAutowiringMetadata()方法(寻找被注解标记的元数据)

             (1)用类名作为cacheKey(缓存建名) 

             (2)使用cacheKey在缓存容器中查找是否有相关缓存 

             (3)如果缓存容器中没有metadata(元数据)|| metadata的class和给定的clazz不符合则重新获取到构建好的metadata实例并放入到缓存容器中(双重锁机制)

        (B)用前面查找到的metadata调用checkConfigMembers方法,需要Spring用默认策略放到的InjectedElements(注入元素表)   

  (5)判断是否是早期引用的bean,如果是,则允许其提前暴露引用(单例、允许循环引用、创建中的bean)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

createBean方法详解 的相关文章

  • 如何将列表转换为地图?

    最近我和一位同事讨论了转换的最佳方式是什么List to Map在 Java 中 这样做是否有任何具体的好处 我想知道最佳的转换方法 如果有人可以指导我 我将非常感激 这是个好方法吗 List
  • 从 Bitmap 类创建 .bmp 图像文件

    我创建了一个使用套接字的应用程序 客户端在其中接收图像并将图像数据存储在 Bitmap 类中 谁能告诉我如何创建一个名为我的图像 png or 我的图像 bmp来自此 Bitmap 对象 String base64Code dataInpu
  • 警告:跳过条目,因为它不是绝对 URI。 NetBeans 中的 GlassFish

    我成功安装了 GlassFish 但是 当我启动服务器时 我收到两条警告消息 警告 跳过条目 因为它不是绝对 URI 那是关于什么的 Launching GlassFish on Felix platform Aug 09 2014 10
  • 使用 java 的 RAR 档案 [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • Jodatime 日期格式

    是否可以格式化 JodaTime 日期 这是代码 private static LocalDate priorDay LocalDate date1 do date1 date1 plusDays 1 while date1 getDayO
  • 将 EditText 聚焦在设备上运行的 PopupWindow 中时出现异常

    我正在为 Android 开发一个弹出窗口 它正在工作 我在上面添加了一个 EditText 和一个按钮 当在 ADV 上运行时 它可以正常工作 而在设备上运行时 当我专注于 EditText 时 这会抛出一个奇怪的异常 android v
  • java.lang.IllegalArgumentException:addChild:子名称“/”不唯一

    java lang IllegalArgumentException addChild 子名称 不唯一 通过在 tomcat webapps 文件夹中启用和禁用 saml 单点登录来替换现有 war 文件时遇到此问题 我正在使用 apach
  • wsdl 没有服务元素

    我必须使用 WCF Web 服务并获得 WSDL 外部的 因此无法控制 WSDL 在 WSDL 定义中 我没有找到包含服务 端口和地址元素的服务元素 WSDL 中不存在这种情况正常吗 这对于 WCF WSDL 来说很常见吗 我正在尝试使用轴
  • 我可以关闭并重新打开套接字吗?

    我学习了一个使用套接字的例子 在此示例中 客户端向服务器发送请求以打开套接字 然后服务器 侦听特定端口 打开套接字 一切都很好 套接字从双方 客户端和服务器 打开 但我仍然不清楚这个东西有多灵活 例如 客户端是否可以关闭一个打开的 从两端
  • Java .split("|") 不工作

    我刚刚遇到了一个问题分割法 http docs oracle com javase 6 docs api java lang String html split 28java lang String 29for 字符串不适用于字符 作为一个
  • Storm Spout 未收到 Ack

    我已经开始使用storm 所以我使用创建简单的拓扑本教程 https github com nathanmarz storm wiki Tutorial 当我运行我的拓扑时LocalCluster一切看起来都很好 我的问题是我没有得到元组的
  • 使用链接列表插入优先级队列的方法

    首先 我觉得我应该提到这是一项作业 我并不是在寻找直接的代码答案 只是为了指出正确的方向 我们被要求在链表中实现优先级队列 我正在努力编写 insert 函数的第一部分 在代码中我尝试检查是否head包含任何内容 如果没有则设置为head
  • Apache Kafka 是否提供异步订阅回调 API?

    我的项目正在将 Apache Kafka 视为老化的基于 JMS 的消息传递方法的潜在替代品 为了让这个过渡尽可能的顺利 如果替代的排队系统 Kafka 有一个异步订阅机制那就更理想了 类似于我们当前项目使用的JMS机制MessageLis
  • Microsoft JDBC 中的 JTDS 属性相当于什么?

    我正在将 JTDS 连接更改为 Microsoft JDBC 并且我看到存在于http jtds sourceforge net faq html http jtds sourceforge net faq htmlMicrosoft JD
  • Checkstyle - 方法按修饰符排序

    是否可以添加到 checkstyle 规则以按修饰符对类中的方法进行排序 我的意思是开头的公共方法和最后的私有方法 MethodsOrderCheck做这个工作 检查文档 https www qulice com qulice checks
  • 如何配置嵌入式 MongoDB 以在 Spring Boot 应用程序中进行集成测试?

    我有一个相当简单的 Spring Boot 应用程序 它公开一个小型 REST API 并从 MongoDB 实例检索数据 对 MongoDB 实例的查询通过基于 Spring Data 的存储库 下面的一些关键代码 Main applic
  • Python 可以替代 Java 小程序吗?

    除了制作用于物理模拟 如抛射运动 重力等 的教育性 Java 小程序之外 还有其他选择吗 如果你想让它在浏览器中运行 你可以使用PyJamas http pyjs org 这是一个 Python 到 Javascript 的编译器和工具集
  • Drools:为什么是无状态会话?

    Drools 使用会话来存储运行时数据 为此 有两种会话 无状态和有状态 与无状态会话相比 有状态会话允许迭代调用 并且似乎比无状态会话具有所有优势 那么为什么会有无状态会话呢 他们服务的目的是什么 与有状态会话相比 它们的优势是什么 谢谢
  • JSP 和 scriptlet

    我知道现在使用 scriptlet 被认为是禁忌 没关系 我会同意Top Star的话 因为我目前只是Java新手 到目前为止我听到的是 它是为了让设计师的生活更轻松 但我想知道 这是否与JSP页面的性能有关 另一方面 如果只是为了 让设计
  • Java,如何管理线程读取socket(websocket)?

    我有一个 WebSocket 服务器 我的服务器创建一个新线程来处理新连接 该线程一直处于活动状态 直到 websocket 中断 我的问题 对于 1 000 000 个连接 我需要 1 000 000 个线程 我如何通过一个线程处理多个

随机推荐

  • zookeeper的Linux下安装和使用 单机版/集群版

    这个是单节点的 集群的在另一篇文章里做了说明 一 解压zookeeper的tar包 二 到zookeeper的conf目录下 拷贝zoo sample cfg 为zoo cfg 记住名字必须叫zoo cfg root VM 0 7 cent
  • 【高级篇 / SDWAN】(7.0) ❀ 07. DNS 解析最快的宽带优先上网 ❀ FortiGate 防火墙

    自从配置SD WAN之后 很多人反应网速变慢了 打开网站卡半天 你有没有接到过这种投诉 其实这是因为DNS解析的原因 由于多条宽带属于不同的运营商 而运营商自带的DNS对自己宽带的解析很快 但对其它宽带就会报错 所以我们只能使用通用DNS
  • 2021-08-06

    在编译OKVIS中 执行make j8时报错的解决方法 1 根据github上OKVIS的安装步骤一步一步执行 由于github经常进不去 我就进了gitee网站查到OKVIS的安装步骤 参考链接 https gitee com bill4
  • vue 引入 二维码

    vue cli3 动态生成二维码 不带logo的 第一步 先下载插件 npm install qrcodejs2 save 第二步 在需要生成二维码的 页面 导入 import QRCode from qrcodejs2 第三步 在页面中引
  • [云原生专题-34]:K8S - 核心概念 - 网络 - Web服务器与反向代理服务器nginx入门介绍

    作者主页 文火冰糖的硅基工坊 文火冰糖 王文兵 的博客 文火冰糖的硅基工坊 CSDN博客 本文网址 https blog csdn net HiWangWenBing article details 122806880 目录 第1章 常见网
  • 深入了解一下C语言scanf()库函数

    目录 一 scanf函数的定义 二 scanf函数的返回值 三 scanf函数的控制符 四 scanf函数控制符的使用 1 一般用法 2 scanf 函数 控制符的用法 2 1 控制符的两种形式 2 2 字符的使用 3 键盘缓冲区残余信息问
  • Confluence 6 管理应用服务器内存设置

    应用服务器中的最小和最大 JVM Heap 空间配置将会影响系统的性能 Confluence 管理员可能希望对默认的配置进行修改 基于你系统的负载不同配置情况也会有所不同 请参考页面 Server Hardware Requirements
  • sed命令常见用法

    常见sed命令的操作 a 增加 在当前行下面增加一行指定内容 c 整行替换 将选定行替换为指定内容 d 删除 删除选定的行 w 将行写入新文件 r 从文件中读取 i 插入 在选定行上面插入一行指定内容 p 打印 如果同时指定行 表示打印指定
  • 五彩斑斓的黑

  • c++操作sqllite

    项目中需要使用的sqllite 有想过使用内存的结果 好像都不大使用 最接近的算是vector了 但是查询方式不大好 而且数据有好几个字段 所以考虑了数据库 sqllite目前已经到了3了 好快 好像这个数据库也不弱 就先用着吧 其实挺简单
  • FPGA—串口RS232(附实现代码)

    目录 1 理论 1 1 串口简介 1 2 RS232信号线 1 3 RS232通信协议简介 2 实操 2 1 硬件资源 2 2 顶层模块 2 2 1 模块说明 2 2 2 RTL 代码 2 2 3 仿真验证 2 3 串口数据接收模块 2 3
  • PyCharm集成SVN,检出、提交代码

    工作需要 使用PyCharm集成SVN 进行代码管理 搜索网上资料 没有讲的很清楚的 自己动手摸索 大致了解了使用方法 遂记录下来 希望他人少走些弯路
  • 比较Opencv自带的frontface检测器

    CascadeClassifier haarcascade frontalface alt new CascadeClassifier xml haarcascade frontalface alt xml CascadeClassifie
  • 【Linux】Linux服务器解决python3.7与openssl的低版本不兼容的问题

    安装了Python3 7之后 遇到的一个很麻烦的坑就是与系统自带的ssl版本不兼容 Python3 7需要的openssl的版本为1 0 2或者1 1 x 这个requirements在config Python3 7的时候使用 with
  • c++栈实现表达式求值

    文章目录 前言 一 思想分析 二 具体实现 前言 后缀表达式的算法思想与具体实现 一 思想分析 设定两个栈 操作数栈 OPND 操作符栈 OPTR 栈初始化 置操作数栈 OPND 为空 操作符栈 OPTR 中预设一个优先级最低的操作符 自左
  • Shell Expect 命令

    expect可以实现shell实现不了的用户交互的需求 expect可以将交互写在一个脚本上 完成很多自动化的动作 比如ssh ftp登陆等 都是需要交互需求的 expect是需要安装的 直接yum y install expect安装即可
  • Class 00 - 学习编程的方法&不同职业所使用的编程语言

    Class 00 学习编程的方法 不同职业所使用的编程语言 学习编程的方法 什么是编程 不同职业所使用的编程语言 数据分析 网页设计 移动应用开发 Web应用开发 游戏开发 Tips 学习编程语言的技巧 从电子表格到 SQL 再到 R 电子
  • threejs学习01-环境搭建+简单示例

    threejs学习 环境搭建 简单示例 环境搭建 node js vite js three js 轻量级的环境 先安装配置好node 在cmd中输入 node v 来查看node版本 node 配置好后就可以创建一个vite的项目了 先调
  • Vuforia Ground Plane 平面识别

    首先弄出这几个组件 如图 还有 再然后 然后就是关键了 如果Vuforia版本低于8 5 8 就得导入ARcore的arr 也就是这个 这个可以在 https dl google com dl android maven2 com goog
  • createBean方法详解

    前言 createBean是创建Bean的主要方法 该方法位于 AbstractBeanFactory的doGetBean方法中的createBean调用 createBean方法流程图 createBean源码解析 protected O