BeanFactory创建过程(基于Servlet)

news2024/11/24 3:51:16

BeanFactory创建过程(基于Servlet)

  • 1. 概述
    • 1.2 那么问题就来了
      • 1.2.1 谁负责AnnotationConfigServletWebServerApplicationContext实例呢?
      • 1.2.2 ApplicationContextFactory初始化过程又是怎么样的?
    • 1.3 总结
  • 2. 最后

1. 概述

AnnotationConfigServletWebServerApplicationContext的类图。
在这里插入图片描述

GenericApplicationContext类有一个构造函数,直接实例化了DefaultListableBeanFactory,它就是BeanFactory

public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry {

    /**
     * Create a new GenericApplicationContext.
     * @see #registerBeanDefinition
     * @see #refresh
    */
    public GenericApplicationContext() {
        this.beanFactory = new DefaultListableBeanFactory();
    }
}

从上面的类图可以看到AnnotationConfigServletWebServerApplicationContext间接的继承了GenericApplicationContext,因为类的继承规则,所以只要创建AnnotationConfigServletWebServerApplicationContext对象,GenericApplicationContext也会被实例化,自然的DefaultListableBeanFactory也会被实例化。

1.2 那么问题就来了

1.2.1 谁负责AnnotationConfigServletWebServerApplicationContext实例呢?

在这里插入图片描述

有一个ApplicationContextFactory工厂类,从上图可以发现它有3个实现类,我们主要看基于注解的实现类AnnotationConfigServletWebServerApplicationContext。可以从下面的实现代码发现,create调用了AnnotationConfigReactiveWebServerApplicationContext无参的构造函数。这个时候问题又来了,ApplicationContextFactory又是怎么初始化的?

static class Factory implements ApplicationContextFactory {

    @Override
    public Class<? extends ConfigurableEnvironment> getEnvironmentType(WebApplicationType webApplicationType) {
        return (webApplicationType != WebApplicationType.REACTIVE) ? null : ApplicationReactiveWebEnvironment.class;
    }

    @Override
    public ConfigurableEnvironment createEnvironment(WebApplicationType webApplicationType) {
        return (webApplicationType != WebApplicationType.REACTIVE) ? null : new ApplicationReactiveWebEnvironment();
    }

    @Override
    public ConfigurableApplicationContext create(WebApplicationType webApplicationType) {
        return (webApplicationType != WebApplicationType.REACTIVE) ? null
            : new AnnotationConfigReactiveWebServerApplicationContext();
    }

}

1.2.2 ApplicationContextFactory初始化过程又是怎么样的?

在这里插入图片描述

spring-boot-2.7.16的jar包中可以发现spring.factories中有下面两行代码,可以使用SpringFactoriesLoader.loadFactories(ApplicationContextFactory.class, getClass().getClassLoader()) 去获取到下面两个对象。

# Application Context Factories
org.springframework.boot.ApplicationContextFactory=\
org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext.Factory,\
org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext.Factory

现在清楚是什么情况了,那就把整个创建的过程走一下。

  1. SpringApplication#run(String…args)
    下面创建的BeanFactory其实就是ConfigurableApplicationContext,其实在ApplicationContextFactory中创建的是AnnotationConfigServletWebServerApplicationContext,从概述的类图中可以看到AnnotationConfigServletWebServerApplicationContext间接的继承了ConfigurableApplicationContext
public ConfigurableApplicationContext run(String... args) {
    long startTime = System.nanoTime();
    DefaultBootstrapContext bootstrapContext = createBootstrapContext();
    ConfigurableApplicationContext context = null;
    configureHeadlessProperty();
    SpringApplicationRunListeners listeners = getRunListeners(args);
    listeners.starting(bootstrapContext, this.mainApplicationClass);
    try {
        ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
        ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
        configureIgnoreBeanInfo(environment);
        Banner printedBanner = printBanner(environment);
        // 这里就是创建BeanFactory的方法
        context = createApplicationContext();
        context.setApplicationStartup(this.applicationStartup);
        prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
        refreshContext(context);
        afterRefresh(context, applicationArguments);
        Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
        if (this.logStartupInfo) {
            new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup);
        }
        listeners.started(context, timeTakenToStartup);
        callRunners(context, applicationArguments);
    }
    catch (Throwable ex) {
        handleRunFailure(context, ex, listeners);
    throw new IllegalStateException(ex);
    }
    try {
        Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);
        listeners.ready(context, timeTakenToReady);
    }
    catch (Throwable ex) {
        handleRunFailure(context, ex, null);
        throw new IllegalStateException(ex);
    }
    return context;
}
  1. SpringApplication#createApplicationContext()
  2. DefaultApplicationContextFactory#create() & getFromSpringFactories()
    SpringApplication#createApplicationContext()方法最终调用了DefaultApplicationContextFactory类的create方法,又调用getFromSpringFactories方法,这个方法就是从spring.factory文件找ApplicationContextFactory的实现类。
public ConfigurableApplicationContext create(WebApplicationType webApplicationType) {
    try {
        return getFromSpringFactories(webApplicationType, ApplicationContextFactory::create,
            AnnotationConfigApplicationContext::new);
    }
    catch (Exception ex) {
        throw new IllegalStateException("Unable create a default ApplicationContext instance, "
            + "you may need a custom ApplicationContextFactory", ex);
    }
}
// 从spring.factory中获取ApplicationContextFactory的实现类
private <T> T getFromSpringFactories(WebApplicationType webApplicationType,
    BiFunction<ApplicationContextFactory, WebApplicationType, T> action, Supplier<T> defaultResult) {
    for (ApplicationContextFactory candidate : SpringFactoriesLoader.loadFactories(ApplicationContextFactory.class,
        getClass().getClassLoader())) {
        // Java8 的写法这里的action就是ApplicationContextFactory的create方法
        // 可以理解为ApplicationContextFactory::create
        // 也可以理解为ApplicationContextFactory.create()
        T result = action.apply(candidate, webApplicationType);
        if (result != null) {
            return result;
        }
    }
    return (defaultResult != null) ? defaultResult.get() : null;
}

1.3 总结

这里来一个小总结,方便记忆。下面是整个过程:

SpringApplication#run -> SpringApplication#createAppliction -> DefaultApplicationContextFactory#create -> DefaultApplicationContextFactory#getFromSpringFactory -> SpringFactoriesLoader#loadFactories

可以知道实例化BeanFactory也就是AnnotationConfigServletWebServerApplicationContextDefaultApplicationContextFactory的实现类去做的,而实例化DefaultApplicationContextFactory是抛给了spring.factory

2. 最后

本篇幅多次提到DefaultListableBeanFactory,下一章就研究研究BeanFactory。还有,解读源码发现很多地方都使用到了工厂设计模式,作者修为浅薄,还不能说出所以然,这也是一个值得思考的问题,等我有了新的想法,会在本篇文章上继续分享。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1424885.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【C++零散小记录】类中重载返回类型为常量引用和非常量引用的函数

#include <iostream>class hyp { public://这里后面必须要加上const修饰符&#xff0c;否则这两个test函数不能重载int const& test() const{std::cout << "const" << std::endl;return num;}//int &test()//{// std::cout << &qu…

吉大计网笔记

Osi七层模型 物理层&#xff1a;比特流的透明传输 数据链路层&#xff1a;ip数据包装成帧并传输&#xff0c;处理相邻节点的数据传输。 网络层&#xff1a;选择路由和交换节点&#xff0c;处理任意节点的数据传输。 运输层&#xff1a;主机进程的数据传输服务&#xff0c;端到端…

雷达DoA估计的跨行业应用--麦克风阵列声源定位(Matlab仿真)

一、概述 麦克风阵列&#xff1a; 麦克风阵列是由一定数目的声学传感器&#xff08;麦克风&#xff09;按照一定规则排列的多麦克风系统&#xff0c;而基于麦克风阵列的声源定位是指用麦克风拾取声音信号&#xff0c;通过对麦克风阵列的各路输出信号进行分析和处理&#xff0c;…

Kubernetes实战(二十一)-event事件持久化

默认情况下&#xff0c; K8S 会将事件保留在 etcd 中一个小时&#xff0c;超过1小时的事件将无法看到&#xff0c;所以 K8S 默认保留事件的时间不足以来更深入的了解集群&#xff0c;所以将事件导出到集群外存储是有必要的&#xff0c;以实现可观测性和告警。 Event事件持久化…

央视见证|“看见中国汽车”走进首家汽车供应链企业东软睿驰

由工业和信息化部支持指导&#xff0c;中国汽车工业协会和央视网联合出品的2023《看见中国汽车》专题东软睿驰篇正式上线&#xff0c;记录品牌向上专项行动走进首家汽车供应链企业&#xff0c;展示东软睿驰围绕“成为OEM 软件定义汽车时代最可信赖的合作伙伴”核心战略的创新发…

IT行业证书大揭秘:哪些证书含金量最高?

文章目录 &#x1f4d6; 介绍 &#x1f4d6;&#x1f4d2; 证书 &#x1f4d2; &#x1f4d6; 介绍 &#x1f4d6; 在IT行业&#xff0c;有许多证书被认为是含金量高的&#xff0c;可以帮助个人在职业发展中取得重要的竞争优势。以下是一些IT行业中被认为含金量高的证书&#x…

信用飞品牌升级——全方位优化用户体验 更周到更暖心

在当今社会,金融科技的迅速发展让信贷服务变得更加便捷。信贷品牌的崛起和发展,正在改变着人们的金融生活。消费者在选择信贷服务时,不仅仅关注信贷的额度和利率,服务体验也成为了一大关注点。一个优秀的信贷品牌,不仅要能满足用户的基本信贷需求,更要在服务体验上赢得用户的认…

基于 Echarts 的 Python 图表库:Pyecahrts交互式的日历图和3D柱状图

文章目录 概述一、日历图和柱状图介绍1. 日历图基本概述2. 日历图使用场景3. 柱状图基本概述4. 柱状图使用场景 二、代码实例1. Pyecharts绘制日历图2. Pyecharts绘制2D柱状图3. Pyecharts绘制3D柱状图 总结 概述 本文将引领读者深入了解数据可视化领域中的两个强大工具&#…

【2024全网最详细】Google 搜索命令终极指南

&#x1f482; 个人网站:【 海拥】【神级代码资源网站】【办公神器】&#x1f91f; 基于Web端打造的&#xff1a;&#x1f449;轻量化工具创作平台&#x1f485; 想寻找共同学习交流的小伙伴&#xff0c;请点击【全栈技术交流群】 你是否尝试过使用 Google 搜索作为免费的 SEO …

【解刊】审稿人极其友好!中科院2区SCI,3个月录用,论文质量要求宽松!

计算机类 • 高分快刊 今天带来Springer旗下计算机领域高分快刊&#xff0c;有投稿经验作者表示期刊审稿人非常友好&#xff0c;具体情况一起来看看下文解析。如有投稿意向可重点关注&#xff1a; 01 期刊简介 Complex & Intelligent Systems ✅出版社&#xff1a;Sprin…

“互联网+水务”——智慧水务2.0推动水务行业产业结构变革

结合国内外水务企业数字化经典实践&#xff0c;探讨智慧水务2.0发展趋势&#xff0c;思考未来“标准体系数字资产使能技术”数字水务的发展态势&#xff0c;为我国水务企业制定和实施有效的数字化转型战略提供参考和借鉴。 通过数据清洗工作&#xff0c;识别并改善数据重复、数…

Linux useradd、gpasswd、chmod 等关于用户及权限设置

创建用户 useradd zen01 useradd zen02 useradd zen03 创建组 groupadd dev-group 把用户添加到dev-group组中 gpasswd -a zen01 dev-group gpasswd -a zen02 dev-group gpasswd -a zen03 dev-group 查看 dev-group组中用户列表 grep ‘dev-group’ /etc/group 创建文件 mkdir…

【go语言】error 错误处理详解

前言 在软件开发中&#xff0c;错误码是一种重要的信息传递方式&#xff0c;对于开发者和用户都具有重要的意义。一般情况下&#xff0c;系统出现故障&#xff0c;由运维在狂轰滥炸的报警信息中找到关键错误信息和研发人员进行沟通&#xff0c;再查看代码逻辑理清问题根源&…

dolist案例实现

这段代码是一个使用Vue.js实现的简单的ToDoList&#xff08;待办事项列表&#xff09;应用。我们分几个部分详细解释这段代码。 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>todolist</title&g…

算法练习01——哈希部分双指针

目录 1. 两数之和(*)242. 有效的字母异位词(easy)49. 字母异位词分组(*)349. 两个数组的交集202. 快乐数(1.使用Set存哈希&#xff0c;2.快慢指针)454. 四数相加 II383. 赎金信15. 三数之和*(双指针)18. 四数之和*(双指针)128. 最长连续序列 1. 两数之和(*) https://leetcode.…

Acwing---797.差分

差分 1.题目2.基本思想3.代码实现 1.题目 输入一个长度为 n n n 的整数序列。 接下来输入 m m m 个操作&#xff0c;每个操作包含三个整数 l , r , c l,r,c l,r,c&#xff0c;表示将序列中 [ l , r ] [l,r] [l,r] 之间的每个数加上 c c c。 请你输出进行完所有操作后的…

2024新利好!一文读懂Shopee 3PF PFF一店多运模式

2023年年底&#xff0c;Shopee平台又有大动作&#xff01;正式上线了3PF PFF一店多运模式&#xff0c;已完成库存管理模式升级的三方仓卖家&#xff0c;即可开启一店多运新模式。 图源&#xff1a;Shopee 一、3PF PFF模式优势解析 三方仓一店多运&#xff08;3PF PFF&#xf…

什么可以用手机蓝牙控制LED???#串口通信【下】

什么可以用手机蓝牙控制LED&#xff1f;&#xff1f;&#xff1f;#串口通信【下】 前言预备知识1.小白玩串口控制的ASSII避坑1.1问题引入1.2解决问题 2.串口支持单词型指令控制2.1实现串口支持单词型指令控制的核心思路2.2利用字符数组来承接单词型指令2.3利用strstr函数来查找…

【Java程序设计】【C00202】基于(JavaWeb+SSM)的信访管理系统(论文+PPT)

基于&#xff08;JavaWebSSM&#xff09;的信访管理系统&#xff08;论文PPT&#xff09; 项目简介项目获取开发环境项目技术运行截图 项目简介 这是一个基于ssm的信访管理系统 本系统分为管理员、信访人员和工作人员3个功能模块。 管理员&#xff1a;管理员登录进入信访管理系…

从0到1入门C++编程——06 类和对象之多态、文件操作

文章目录 多态1.多态基本概念2.多态案例——计算器3.纯虚函数和抽象类4.多态案例——制作饮品5.虚析构和纯虚析构6.多态案例——电脑组装 文件操作1.文本文件--写文件2.文本文件--读文件3.二进制文件--写文件4.二进制文件--读文件 多态 1.多态基本概念 多态是C面向对象的三大…