Spring源码-启动过程

[Spring Boot] 1. Spring Boot启动过程源码分析 关于Spring Boot,已经有很多介绍其如何使用的文章了,本文从源代码(基于Spring-boot 1.5.6)的角度来看看Spring Boot的启动过程到底是怎么样的,为何以往纷繁复杂的配置到如今可以这么简便。1. 入口类package com.example.demo;import org.springframework.boot.SpringApplication; import org 阅读详情

Spring源码分析(一)-Spring环境的初始化

Spring的框架特征

以下摘自知道词条
控制反转——Spring通过一种称作控制反转(IoC)的技术促进了低耦合。当应用了IoC,一个对象依赖的其它对象会通过被动的方式传递进来,而不是这个对象自己创建或者查找依赖对象。你可以认为IoC与JNDI相反——不是对象从容器中查找依赖,而是容器在对象初始化时不等对象请求就主动将依赖传递给它。
面向切面——Spring提供了面向切面编程的丰富支持,允许通过分离应用的业务逻辑与系统级服务(例如审计(auditing)和事务(transaction)管理)进行内聚性的开发。应用对象只实现它们应该做的——完成业务逻辑——仅此而已。它们并不负责(甚至是意识)其它的系统级关注点,例如日志或事务支持。
容器——Spring包含并管理应用对象的配置和生命周期,在这个意义上它是一种容器,你可以配置你的每个bean如何被创建——基于一个可配置原型(prototype),你的bean可以创建一个单独的实例或者每次需要时都生成一个新的实例——以及它们是如何相互关联的。然而,Spring不应该被混同于传统的重量级的EJB容器,它们经常是庞大与笨重的,难以使用。
框架——Spring可以将简单的组件配置、组合成为复杂的应用。在Spring中,应用对象被声明式地组合,典型地是在一个XML文件里。Spring也提供了很多基础功能(事务管理、持久化框架集成等等),将应用逻辑的开发留给了你。
MVC——Spring的作用是整合,但不仅仅限于整合,Spring 框架可以被看做是一个企业解决方案级别的框架。客户端发送请求,服务器控制器(由DispatcherServlet实现的)完成请求的转发,控制器调用一个用于映射的类HandlerMapping,该类用于将请求映射到对应的处理器来处理请求。HandlerMapping 将请求映射到对应的处理器Controller(相当于Action)在Spring 当中如果写一些处理器组件,一般实现Controller 接口,在Controller 中就可以调用一些Service 或DAO 来进行数据操作 ModelAndView 用于存放从DAO 中取出的数据,还可以存放响应视图的一些数据。 如果想将处理结果返回给用户,那么在Spring 框架中还提供一个视图组件ViewResolver,该组件根据Controller 返回的标示,找到对应的视图,将响应response 返回给用户。
我们将分章节介绍Spring是如何实现这些功能的。

Spring是如何初始化的

我们知道在WEB项目中集成Spring是需要在web.xml中添加一个监听器

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

非Web项目:

java
public static void main(String[] args) {

//所有配置文件
args = new String[] {
"classpath:spring/spring-servlet.xml",
"classpath:spring/ApplicationContext.xml",
"classpath:spring/mybatis-config.xml",
};
ApplicationContext actx = new ClassPathXmlApplicationContext(args);
//得到类的实例
UserService userService = (UserService) actx.getBean("userService");
//调用类的方法
userService.deleteUser(2);
}

这里先以非Web项目为准,虽说Spring最长使用场景是在Web项目中,但是非Web项目这种用法更直接,更易跟踪。

看一下这个构造方法,歌词大意是创建一个ClassPathXmlApplicationContext,并从指定的配置文件加载定义,并自动的刷新Context(上下文)

java
    /**
     * Create a new ClassPathXmlApplicationContext, loading the definitions
     * from the given XML file and automatically refreshing the context.
     * @param configLocation resource location
     * @throws BeansException if context creation failed
     */
    public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
        this(new String[] {configLocation}, true, null);
    }

跟踪下来看看多参构造器

java
    /**
     * Create a new ClassPathXmlApplicationContext with the given parent,
     * loading the definitions from the given XML files.
     * @param configLocations array of resource locations
     * @param refresh whether to automatically refresh the context,
     * loading all bean definitions and creating all singletons.
     * Alternatively, call refresh manually after further configuring the context.
     * @param parent the parent context
     * @throws BeansException if context creation failed
     * @see #refresh()
     */
    public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
            throws BeansException {

        super(parent); 
        setConfigLocations(configLocations);
        if (refresh) {
            refresh();
        }
    }

super(ApplicationContext parent) 暂时不管,因为我们通过那个构造器转进来,parent参数是null
setConfigLocations(configLocations); 这个是初始化context中的配置文件路径
refresh() 追进去看下

其实这个方法定义在父类org.springframework.context.support.AbstractApplicationContext 中,从这代码的书写方式上是可以看出Spring一些加载流程的(中文我自己加的,渣英语)

java
@Override
    public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            // Prepare this context for refreshing. //为正在进行的刷新准备bean工厂
            prepareRefresh();

            // Tell the subclass to refresh the internal bean factory. //告诉子类去刷新内部的beanFactory
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

            // Prepare the bean factory for use in this context.  
            // 在当前上下文中,准备Bean工厂
            prepareBeanFactory(beanFactory);

            try {
                // Allows post-processing of the bean factory in context
                // subclasses.
                // 在bean被装载后,提供一个修改BeanFactory的入口  ,即允许子类做一些后处理
                postProcessBeanFactory(beanFactory);

                // Invoke factory processors registered as beans in the context.
                invokeBeanFactoryPostProcessors(beanFactory);

                // Register bean processors that intercept bean creation.
                registerBeanPostProcessors(beanFactory);

                // Initialize message source for this context.
                initMessageSource();

                // Initialize event multicaster for this context.
                // 初始化上下文事件广播
                initApplicationEventMulticaster();

                // Initialize other special beans in specific context
                // subclasses.
                // 模版方法
                onRefresh();

                // Check for listener beans and register them.
                // 检查是否有监听器bean并注册他们
                registerListeners();

                // Instantiate all remaining (non-lazy-init) singletons.
                // 实例化所有的非懒加载的单例
                finishBeanFactoryInitialization(beanFactory);

                // Last step: publish corresponding event.
                // 最后一步,发布相关事件
                finishRefresh();
            }

            catch (BeansException ex) { //异常处理
                if (logger.isWarnEnabled()) { 
                    logger.warn("Exception encountered during context initialization - "
                            + "cancelling refresh attempt: " + ex);
                }

                // Destroy already created singletons to avoid dangling
                // resources.
                // 销毁一些已经创建的bean
                destroyBeans();

                // Reset 'active' flag.
                // 重置'active'标记
                cancelRefresh(ex);

                // Propagate exception to caller.
                throw ex;
            }

            finally {
                // Reset common introspection caches in Spring's core, since we
                // might not ever need metadata for singleton beans anymore...
                resetCommonCaches();
            }
        }
    }

从以上代码,大概可知一个Spring上下文启动或刷新的过程

java
/**
     * Prepare this context for refreshing, setting its startup date and active
     * flag as well as performing any initialization of property sources.
     */
    protected void prepareRefresh() {
        this.startupDate = System.currentTimeMillis();
        this.closed.set(false); //AtomicBoolean 类型 
        this.active.set(true);  //AtomicBoolean 类型 

        if (logger.isInfoEnabled()) {
            logger.info("Refreshing " + this);
        }

        // Initialize any placeholder property sources in the context
        // environment
        initPropertySources();

        // Validate that all properties marked as required are resolvable
        // see ConfigurablePropertyResolver#setRequiredProperties
        getEnvironment().validateRequiredProperties();

        // Allow for the collection of early ApplicationEvents,
        // to be published once the multicaster is available...
        this.earlyApplicationEvents = new LinkedHashSet<ApplicationEvent>();
    }

obtainFreshBeanFactory 看方法名是一个刷新Bean工厂的方法,其方法签名为 protected ConfigurableListableBeanFactory obtainFreshBeanFactory()
结合Spring源码注释 “Tell the subclass to refresh the internal bean factory.” ,方法含义为刷新并返回内部BeanFactory工厂

/**
     * Tell the subclass to refresh the internal bean factory.
     * @return the fresh BeanFactory instance
     * @see #refreshBeanFactory()
     * @see #getBeanFactory()
     */
    protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
        refreshBeanFactory(); //静态方法,子类覆写
        ConfigurableListableBeanFactory beanFactory = getBeanFactory(); //静态方法子类覆写
        if (logger.isDebugEnabled()) {
            logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
        }
        return beanFactory;
    }

那么实现该方法的子类是谁呢?,回到ClassPathXmlApplicationContext,看看其UML图
这里写图片描述
查看refreshBeanFactory的子类覆写情况,如图,明显是org.springframework.context.support.AbstractRefreshableApplicationContext 这个类
这里写图片描述

通过代码看看BeanFactory是如何刷新的

/**
     * This implementation performs an actual refresh of this context's underlying
     * bean factory, shutting down the previous bean factory (if any) and
     * initializing a fresh bean factory for the next phase of the context's lifecycle.
     */
    @Override
    protected final void refreshBeanFactory() throws BeansException {
        if (hasBeanFactory()) {//判断是否已经有BeanFactory
            destroyBeans();  //销毁单例bean,代码(getBeanFactory().destroySingletons()),具体是如何销毁的由具体的BeanFactory去实现
            closeBeanFactory(); //关闭BeanFactory,直接设置实例变量(this.beanFactory)的引用为null
        }
        try {
            DefaultListableBeanFactory beanFactory = createBeanFactory(); //创建一个新的BeanFactory
            beanFactory.setSerializationId(getId());
            customizeBeanFactory(beanFactory); //干了两个事,1:allowBeanDefinitionOverriding(是否允许ID相同的Bean覆盖,不指定时默认为true) 2.allowCircularReferences(是否允许循环引用,不指定时默认为true)
            loadBeanDefinitions(beanFactory); //加载Bean的定义(读取配置文件,并向bean工厂中注册Bean)customizeBeanFactory中设置的作用会在读取Bean定义并注册的时候体现
            synchronized (this.beanFactoryMonitor) {
                this.beanFactory = beanFactory; //将新的Bean工厂注册给当前的Context
            }
        }
        catch (IOException ex) {
            throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
        }
    }

createBeanFactory();方法中创建了一个beanFactory,Factory实现与层级结构暂不分析,只看Spring的启动准备,loadBeanDefinitions(beanFactory);加载并注册Bean,refreshBeanFactory()主要干了两个事,先把Context中原来的工厂干掉,在重新创建和初始化一个新的Beanfactory.

LLVM实战:如何用Clang+LLVM打造你的第一个C++编译器(附完整配置步骤) 本文详细介绍了如何使用Clang+LLVM构建C++编译器的完整配置步骤,从环境准备到编译流程剖析,再到调试与优化技巧。通过实战指南,帮助开发者深入理解LLVM编译器框架的工作原理,并掌握交叉编译与性能分析等高级功能。 阅读详情

相关推荐

Maya ACES工作流程配置(Arnold 及 RedShift 贴图配置规范-还原出SP-Aces流程下贴图正确的效果) PS还原Aces流程下渲染的图

*如果使用SP,项目工程如果新建的时候设置的就是Aces的流程的话,按规范正常导出即可,贴图会带上相对应的后缀,然后贴图导入材质球的时候会根据后缀自动设置相对应的色彩空间;**万一不是,就自己手动设置一下对应的色彩空间即可;然后点击选择当前的或者选择全部导入的贴图,点击右下角后,开始转换;我复制了一下,一个默认没有LUT的效果,然后另外一个是加载2个LUT后的还原效果,和渲染的效果应该是没有区别的,至少我没有看出明显的区别;把需要转换的贴图拖拽到左侧,然后右面选择需要转换到的相对应的色彩空间;...

Yuulily 7993

Spring之启动过程源码解析

Spring启动过程源码解析

2201_75955594的博客 1076

向量库深度解析:选型、索引原理与生产实践

本文系统解析五大主流向量库(pgvector、Milvus、Weaviate、ChromaDB、Faiss)的定位、优缺点与适用场景,深入拆解FLAT、IVF、HNSW等核心索引原理,并重点分析Milvus的Compaction机制。针对数据治理场景,提供精准选型建议:中小规模优先pgvector或Weaviate,超大规模选择Milvus,开发测试推荐ChromaDB。核心索引推荐HNSW,兼顾检索速度与召回率。全文从理论到实践,为开发者提供清晰的向量库选型逻辑与生产落地指南。

a123147abc的博客 360

Spring源码环境搭建及启动

Spring源码项目搭建及启动,源码项目搭建过程中问题解决。

weixin_44406041的博客 1215

内存管理(二)——内存分段

内存分段

weixin_43844995的博客 2693

PFC中pb模型实战:从胶结参数设置到破坏模拟全流程解析

本文详细解析了PFC软件中平行胶结模型(PB模型)的实战应用全流程。从胶结参数(pb_kn, pb_ks, pb_ten等)的物理意义与精准赋值入手,深入探讨了模型构建、胶结施加以避免初始损伤的技巧,并系统介绍了破坏过程的监测、阈值判定方法以及高级可视化与常见问题诊断。旨在帮助岩土工程与颗粒材料研究者掌握从参数调试到破坏模拟的核心操作,提升数值模拟的准确性与效率。

php55的博客 1074

Spring框架浅析之源码运行

Spring框架浅析之源码运行

李永志的博客 1215

CMIP6数据处理及在气候变化、水文、生态等领域中的应用

CMIP6、Biome-BGC、生态、气候变化、气象、水文、气候模式、植被、生态模式、遥感、极端气候、降水、WRF模式、动力降尺度、RCM、大气环流模型、贝叶斯模型、、降尺度

PhyliciaFelicia的博客 1545

Spring源码分析:启动流程

对于 Spring 启动流程和 Bean 的生命周期,总有一些小地方搞的不是很清楚,干脆直接通过修改代码增加日志输出,使用断点单步调试,把整个流程捋顺了。

初听不知曲中意,再听已是曲中人。 696

VR大空间开发前期,设备选项与流程

欢迎开发者加入 VR 大空间开发之旅!本系列教程将以 Pico 和 HTC 设备为核心,系统拆解从基础搭建到功能实现的全流程,助你快速掌握开发要点。本系列共 12 篇,专为有编程基础但缺乏大空间开发经验的开发者设计。前 7 篇针对 Pico 和 HTC 设备差异分别讲解,后续步骤通用。核心目录如下:​1. 空间环境要求 - 灯光设置 - 场地面积规划 - 识别图案设计2. 网络部署方案3. 客户端体验模式解析 - 一体机模式 - 云渲染模式 - 背包体验模式4. Pico空间录制方法

unitygroup的博客 1352

【WorkBuddy专栏25】如何选择大模型——积分消耗、用途场景、选型决策全指南

【WorkBuddy专栏25】如何选择大模型——积分消耗、用途场景、选型决策全指南

AI人人懂 935

spring启动流程源码

spring容器启动流程: BeanDefinitionReader 配置文件的读取:(xml、yaml、json、properties) public void refresh() throws BeansException, IllegalStateException { synchronized(this.startupShutdownMonitor) { /** * 1.准备上下文的刷新工作,记录bean容器的启动时间,容器活跃状态 *

qq_38923630的博客 929

MIKE 21 教程 2.2 Domain, Time, Module Selection设置教学

上一节讲解了水动力模型的基本概念与文件创建MIKE 21 教程 2.1水动力模型介绍​本节讲解水动力模型前三个模块的设置此模块需导入之前绘制好的网格文件,导入后可预览网格文件点击上方的Domain Specification可查看网格的数据统计与高程属性,快速检查网格文件有无明显错误 点击上方的Boundary names,可查看之前定义的出入水边界。在网格文件中,我们对边界只能以数字属性进行区分,这里可以对数字属性进行命名,在name中直接修改即可。本实例中我们的2代表入水边界,3代表出水边界。因为博主日

Hello Word 3865

Spring之启动过程源码

Spring框架的事件发布机制是一种用于在应用程序内部模块之间进行松散耦合通信的机制。它允许一个组件发布事件,而其他组件监听并响应这些事件,从而实现模块之间的解耦。事件可以是任何Java对象,而事件的发布者和监听者之间不需要直接的引用。事件(Event): 事件是一个普通的Java对象,它封装了与应用程序相关的状态信息。通常,事件类包含了一些数据或者消息,用于传递给监听者。事件发布者(Event Publisher): 事件发布者是负责发布事件的组件。

qq_43456605的博客 1393

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

pscad IEEE标准系统搭建说明

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

【Spring】Spring Boot启动过程源码解析

本文深入解析SpringBoot启动流程,从入口类分析到完整容器初始化过程。启动过程分为两大阶段:1) SpringApplication构造阶段,完成应用类型判断、初始化器和监听器加载;2) run方法执行阶段,包含9个关键步骤:环境准备、Banner打印、容器创建、前置处理、容器刷新、后置处理等。重点剖析了事件发布机制(如ApplicationStartingEvent)、配置加载优先级、自动配置原理等核心机制,并指出初始化器和监听器通过spring.factories加载的特殊性。

小七的博客 1314

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

Spring 源码启动过程

重复?什么和什么重复?spring spi 自动根据依赖装配的实例和注解配置类里自己实例化的类实例 重复解决思路 在配置类实例化的过程中判断是否需要加载,需要加载就加载,不需要加载就不加载如何判断是否需要加载?判断加载是否重复->判断spring容器是否已经存在,如果已经存在了就重复如何判断spring容器中是否已经存在 通过类加载器@Cinfigrtion 里的bean通过条件注解类,用类加载器加载器判断当前类有无重复的核心类的容器,有就不加载容器,没有就加载@Condition。

weixin_44410940的博客 776

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

浅析 Spring 启动过程:从源码到核心方法

通过对 Spring 启动过程的源码分析,我们对 Spring 框架的工作原理有了更深入的理解。无论是在开发过程中优化应用性能,还是在遇到问题时进行排查,掌握这些知识都能让我们更加得心应手。

qq_45464560的博客 1222

Spring全家桶源码解析--2.7 Spring启动过程

了解Spirng 的启动过程,可以知晓Spring 中对于BeanDefinition 的生成和不同类型bean 的创建工作,了解bean 的前置后置处理器,可以在定义bean 的时候知晓其工作的原理。invokeBeanFactoryPostProcessors 扫描生成bean 定义:通过beanFactory 的后置处理器去扫描生成bean 定义// 调用 beanFactory 的后置处理器if (!

拽着尾巴的鱼儿的博客 376

通过ClassPathXmlApplicationContext源码解读Spring启动过程

通过ClassPathXmlApplicationContext源码解读Spring启动过程 @(Spring)[Spring][源码] 注:本次分析基于spring-context-5.1.0.RC1.jar 通过ClassPathXmlApplicationContext源码解读Spring启动过程 类关系 入口函数 解读refresh方法 prepareRefresh() ...

Loong 1656

深入剖析Spring Boot启动过程:从源码到实践

在当今Java生态系统中,Spring Boot已经成为企业级应用开发的事实标准。作为Spring Framework的扩展,它通过约定优于配置的理念,极大地简化了基于Spring的应用开发流程。理解Spring Boot的启动机制,不仅能够帮助开发者更好地驾驭这个框架,还能在遇到问题时快速定位和解决。

zuiyuelong的博客 1048

手写模拟Spring源码启动过程

在语言模型中,编码器和解码器都是由一个个的 Transformer 组件拼接在一起形成的。提供先进的推理,复杂的指令,更多的创造力。

qq_27740127的博客 152

【SpringBoot】深入剖析 Spring Boot 启动过程(附源码与实战)

我们可以自定义来监听 Spring Boot 启动过程,并记录日志。Spring Boot 启动的核心入口是,它完成环境准备、容器创建、事件发布等步骤。核心组件包括,它们协同完成应用初始化。我们可以自定义,监听 Spring Boot 启动事件,实现日志记录或其他增强功能。Spring Boot 的启动过程是一个标准化的“模板方法模式”实现,每一步都可以通过扩展点进行自定义,极大增强了框架的可扩展性。希望本篇文章能帮助你更好地理解 Spring Boot 的启动原理!📌你学会了吗?

工一木子 880

Spring源码解析——启动过程详解

基于Spring的启动看看Spring 进行了哪些操作,在前面简单写过,现在详细概述一次。 AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class); System.out.println(applicationContext.getBean("userService")); 进入AnnotationConfigApplicationCo

qq_43843037的博客 478

Spring源码之启动过程(一)—— 容器的启动

registerAnnotationConfigProcessors()方法 所属类:org.springframework.context.annotation.AnnotationConfigUtils public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors( BeanDefinitionRegistry registry, @Nullable Object source) { ..

奔跑的蜗牛_Kieasr 1486

Spring源码系列:Spring的启动过程

Spring对于程序员说来说都不陌生;作为一个强大的开源技术,帮助我们能够更好的进行项目的开发与维护。直接进入主题吧。Spring的启动过程实际上就是Ioc容器初始化以及载入Bean的过程;本文主要是学习记录下前半部分(Ioc容器的初始化),新手上路,如有错误,请指正!1.从配置文件说起 <listener> <listener-class>org.spr...

菜鸟路上的小白 1839

【Spring】Spring之启动过程源码解析

Spring之启动过程源码解析

持续学习,坚持原创,分享技术笔记及经验。 626
上一篇: gradle安装配置指路
下一篇: Spring源码阅读之-bean的解析与注册
weiythi
博客等级 码龄16年 23粉丝 48原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值