侧边栏壁纸
博主头像
再见理想博主等级

只争朝夕,不负韶华

  • 累计撰写 112 篇文章
  • 累计创建 64 个标签
  • 累计收到 4 条评论

目 录CONTENT

文章目录

Springboot 启动流程

再见理想
2022-12-12 / 0 评论 / 0 点赞 / 626 阅读 / 1,446 字

一,Springboot 启动整体流程

Spring Boot 能够让你非常容易的创建一个基于 spring framework 的应用,以最小的代价开始一个项目。

Springboot 的启动,主要创建了配置环境、事件监听、应用上下文,并基于以上条件,在容器中开始实例化、初始化我们需要的 Bean。主要流程包括两步骤,创建并初始化 SpringApplication 和执行 run 方法。

@SpringBootApplication
public class ApiApplication {
    public static void main(String[] args) {
        //启动类静态run方法
        SpringApplication.run(ApiApplication.class, args);
    }
}

1.创建并初始化 SpringApplication

  1. SpringApplication 对象在初始化时,从类路径中推断并设置应用类型。应用类型有三种:非 web 应用,基于servlet 的 web 应用和基于 REACTIVE 的 web 应用;
  2. 从 SpringFactories 文件中找到配置的事件监听器,并保存起来;
  3. 推断运行主类;

2.执行run方法

  1. 创建了应用的监听器 SpringApplicationRunListeners 并开始监听;
  2. 加载 SpringBoot 配置环境(ConfigurableEnvironment),如果是通过web容器发布,会加载StandardEnvironment,其最终也是继承了ConfigurableEnvironment;
  3. 创建run方法的返回对象:ConfigurableApplicationContext(应用配置上下文),ConfigurableApplicationContext 是 ApplicationContext 的子类,该接口的主要任务就是配置应用上下文功能。
  4. 回到 run 方法内,prepareContext 方法将 listeners、environment、applicationArguments、banner 等重要组件与上下文对象关联;
  5. 接下来的 refreshContext(context) 方法是实现自动化配置的关键,包括 spring.factories 的加载,bean 的实例化等核心工作;
  6. 启动监听器,通知程序运行。

二,构造方法

// SpringApplication.java
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
    // 省略...
    this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));
    // 确定application类型
    this.webApplicationType = WebApplicationType.deduceFromClasspath();
    // 加载初始化容器
  this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
    // 找到配置的事件监听器,并保存起来
    this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
    // 推断运行主类
    this.mainApplicationClass = this.deduceMainApplicationClass();
}

三,执行run() 方法

创建完 SpringApplication 实例之后,继续执行 run 方法,run方法的源码如下:

// org.springframework.context.ConfigurableApplicationContext	
public ConfigurableApplicationContext run(String... args) {
    //1.开启程序启动计时器
    long startTime = System.nanoTime();
    DefaultBootstrapContext bootstrapContext = createBootstrapContext();
    ConfigurableApplicationContext context = null;
    //2.无输入不影响工作
    configureHeadlessProperty();
    //3.获取监听器
    SpringApplicationRunListeners listeners = getRunListeners(args);
    //4.启动监听器
    listeners.starting(bootstrapContext, this.mainApplicationClass);
    try {
        //5.设置程序启动参数
        ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
        //6.配置环境
        ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
        //7.跳过bean检索
        configureIgnoreBeanInfo(environment);
        //8.打印banner
        Banner printedBanner = printBanner(environment);
        //9.创建应用程序上下文
        context = createApplicationContext();
        context.setApplicationStartup(this.applicationStartup);
        // 将listeners、environment、applicationArguments、banner等重要组件与上下文关联
        prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
        //10.刷新上下文,完成对 Bean 的扫描、实例化、初始化(重要)
        refreshContext(context);
        //11.上下文后置处理
        afterRefresh(context, applicationArguments);
        //12.结束计时器
        Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
        if (this.logStartupInfo) {
            new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup);
        }
        //13.启动监听器
        listeners.started(context, timeTakenToStartup);
        //14.通知程序运行
        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;
}

四,refresh() 源码分析

#refresh() 方法,是定义在 ConfigurableApplicationContext 类中的,作用就是:刷新 Spring 的应用上下文。在这个方法中,完成对 Bean 的扫描、实例化、初始化。

// org.springframework.context.support.AbstractApplicationContext#refresh
@Override
public void refresh() throws BeansException, IllegalStateException {
	synchronized (this.startupShutdownMonitor) {
		// 1 准备刷新上下文环境,对系统的环境变量或者系统属性进行准备和校验
		prepareRefresh();
		// 2 创建并初始化 BeanFactory
		ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
		// 3 填充BeanFactory功能
		prepareBeanFactory(beanFactory);
		try {
			// 4 提供子类覆盖的额外处理,即子类处理自定义的BeanFactoryPostProcess
			postProcessBeanFactory(beanFactory);
			// 5 激活各种BeanFactory处理器,找到并加载BeanFactoryPostProcessor实现类
            // 加载BeanDefinition放入到BeanDefinitionMap中
			invokeBeanFactoryPostProcessors(beanFactory);
			// 6 注册拦截Bean创建的Bean处理器,即注册 BeanPostProcessor
			registerBeanPostProcessors(beanFactory);
			// 7 初始化上下文中的资源文件,如国际化文件的处理等
			initMessageSource();
			// 8 初始化上下文事件广播器
			initApplicationEventMulticaster();
			// 9 给子类扩展初始化其他Bean,预留给 AbstractApplicationContext 的子类用于
            // 初始化其他特殊的 bean,该方法需要在所有单例 bean 初始化之前调用。
			onRefresh();
			// 10 在所有bean中查找listener bean,然后注册到广播器中
			registerListeners();
			// 11 实例化、初始化剩下的单例Bean(非延迟加载的)
			finishBeanFactoryInitialization(beanFactory);
			// 12 完成刷新过程,通知生命周期处理器lifecycleProcessor刷新过程
            // 主要调用 LifecycleProcessor#onRefresh() ,并发布事件ContextRefreshedEvent
			finishRefresh();
		} catch (BeansException ex) {
			if (logger.isWarnEnabled()) {
				logger.warn("Exception encountered during context initialization - " +
						"cancelling refresh attempt: " + ex);
			}
			//  13 销毁已经创建的Bean
			destroyBeans();
			// 14 重置容器激活标签
			cancelRefresh(ex);
			//抛出异常
			throw ex;
		} finally {
			// Reset common introspection caches in Spring's core, since we
			// might not ever need metadata for singleton beans anymore...
			resetCommonCaches();
		}
	}
}

第5步分析

invokeBeanFactoryPostProcessors(beanFactory) 方法,激活各种 BeanFactory 处理器,会去调用ConfigurationClassPostProcessor 这个bean工厂的后置处理器完成扫描,将加载的 BeanDefinition 放入BeanDefinitionMap 中。

执行完此方法后,可以看到已将扫描的BeanDefinition放入到了BeanDefinitionMap中,org.springframework.context.support.PostProcessorRegistrationDelegate#invokeBeanDefinitionRegistryPostProcessors

第11步分析

finishBeanFactoryInitialization(beanFactory) 方法,实例化、初始化剩下的单例Bean(非延迟加载的)

// org.springframework.context.support.AbstractApplicationContext#finishBeanFactoryInitialization
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
        // 省略...
    	// 开始实例化
        beanFactory.preInstantiateSingletons();
    }

preInstantiateSingletons() 方法中,调用 getBean(beanName) 方法区获取 bean,getbean流程可以参考以下文章:Spring 如何处理循环依赖文章:创建Bean完整流程,完成对 Bean 的实例化,属性填充(在这里处理循环依赖问题)以及初始化。

refresh() 流程图

0

评论区