68.原理解析-SpringBoot完整启动过程

计时

在将启动器,引导器,初始化器保存和确定了主类之后,返回最准确的可用系统计时器的当前值,以毫微秒为单位。

long startTime = System.nanoTime();

在这里插入图片描述

接着创建引导上下文(Context环境)
DefaultBootstrapContext bootstrapContext = createBootstrapContext();
进入createBootstrapContext()中查看源代码:
   

private DefaultBootstrapContext createBootstrapContext() {
     //首先创建DefaultBootstrapContext对象,保存信息。
       DefaultBootstrapContext bootstrapContext = new DefaultBootstrapContext();
    //接着获取之前所有的initializer并执行initialize(bootstrapContext)),来完成对引导启动器的环境设置让当前应用进入headless模式
       this.bootstrapRegistryInitializers.forEach((initializer) -> initializer.initialize(bootstrapContext));
       return bootstrapContext;
   }

在这里插入图片描述

java.awt.headless

configureHeadlessProperty();

private void configureHeadlessProperty() {
      System.setProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS,
              System.getProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, Boolean.toString(this.headless)));
  }

 

//获取所有运行监听器(为了方便所有Listener进行事件感知)
SpringApplicationRunListeners listeners = getRunListeners(args);



获取运行监听器的具体方法
源代码中依然是getSpringFactoriesInstances,从spring.factories中寻找SpringApplicationRunListener.class
    

private SpringApplicationRunListeners getRunListeners(String[] args) {
       Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
       return new SpringApplicationRunListeners(logger,
               getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args),
               this.applicationStartup);
   }

listeners.starting,遍历所有监听器,并且starting
doWithListeners中的foreach方法。
也相当于通知所有感兴趣(需要这个信息)系统正在启动的“人”,项目正在starting

void starting(ConfigurableBootstrapContext bootstrapContext, Class<?> mainApplicationClass) {
        doWithListeners("spring.boot.application.starting", (listener) -> listener.starting(bootstrapContext),
                (step) -> {
                    if (mainApplicationClass != null) {
                        step.tag("mainApplicationClass", mainApplicationClass.getName());
                    }
                });
    }

/**
进入doWithListeners
*/
    private void doWithListeners(String stepName, Consumer<SpringApplicationRunListener> listenerAction,
            Consumer<StartupStep> stepAction) {
        StartupStep step = this.applicationStartup.start(stepName);
        this.listeners.forEach(listenerAction);
        if (stepAction != null) {
            stepAction.accept(step);
        }
        step.end();
    }


进入try中的执行
首先是保存命令行中所有的参数

ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);

 

准备环境信息

ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);


//方法体👇

 

private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
            DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {
        // Create and configure the environment,有环境信息就获取=
        ConfigurableEnvironment environment = getOrCreateEnvironment();
        //getOrCreateEnvironment,返回或创建基础环境信息对象
        configureEnvironment(environment, applicationArguments.getSourceArgs());
        //配置环境,通过命令行参数和环境信息
        ConfigurationPropertySources.attach(environment);
        //绑定信息,也就是保存工作
        listeners.environmentPrepared(bootstrapContext, environment);
        //listeners就是之前获取到的所有的RunListener,通知所有监听器当前环境准备完成
        DefaultPropertiesPropertySource.moveToEnd(environment);
        Assert.state(!environment.containsProperty("spring.main.environment-prefix"),
                "Environment prefix cannot be set via properties.");
        bindToSpringApplication(environment);
        //绑定工作
        if (!this.isCustomEnvironment) {
            environment = convertEnvironment(environment);
        }
        
        ConfigurationPropertySources.attach(environment);
        return environment;
    }



而在配置环境信息时:在更深层的调用方法configurePropertySources中有MutablePropertySources sources=environment.getPropertySources();能够获取@PropertySource,读取到外部的配置文件,也就是说此方法加载全系统中所有的配置信息!
而在之后,如果有命令行中的信息也会添加进配置中
总结准备环境信息
读取所有配置源的配置属性值
configurePropertySources

通知
监听器调用listeners.environmentPrepared(bootstrapContext, environment);通知所有监听器当前环境准备完成

绑定环境信息

配置需要忽略的环境信息
configureIgnoreBeanInfo(environment);

打印banner
Banner printedBanner = printBanner(environment);

创建IOC容器!
context = createApplicationContext();

步入createApplicationContext
protected ConfigurableApplicationContext createApplicationContext() {
        return this.applicationContextFactory.create(this.webApplicationType);
    }

 

根据当前项目类型(Servlet)创建
当前则会创建AnnotationConfigServletWebServerApplicationContext();
在这里插入图片描述
在这里插入图片描述

记录当前事件
context.setApplicationStartup(this.applicationStartup);

准备IOC容器信息(准备ApplicationContext)
prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);

进入prepareContext

private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context,
           ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
           ApplicationArguments applicationArguments, Banner printedBanner) {
       context.setEnvironment(environment);
       //设置环境
       postProcessApplicationContext(context);
       //保存基本环境信息
       applyInitializers(context);
       listeners.contextPrepared(context);
       bootstrapContext.close(context);
       if (this.logStartupInfo) {
           logStartupInfo(context.getParent() == null);
           logStartupProfileInfo(context);
       }
       // Add boot specific singleton beans
       ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
       beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
       if (printedBanner != null) {
           beanFactory.registerSingleton("springBootBanner", printedBanner);
       }
       if (beanFactory instanceof AbstractAutowireCapableBeanFactory) {
           ((AbstractAutowireCapableBeanFactory) beanFactory).setAllowCircularReferences(this.allowCircularReferences);
           if (beanFactory instanceof DefaultListableBeanFactory) {
               ((DefaultListableBeanFactory) beanFactory)
                       .setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
           }
       }
       if (this.lazyInitialization) {
           context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
       }
       // Load the sources
       Set<Object> sources = getAllSources();
       Assert.notEmpty(sources, "Sources must not be empty");
       load(context, sources.toArray(new Object[0]));
       listeners.contextLoaded(context);
   }



保存基本环境信息
context.setEnvironment(environment);

IOC容器的后置处理流程
postProcessApplicationContext(context);
像注册一些组件,读取配置文件的资源,资源的加载器

应用初始化器applyInitializers(context);
遍历所有的ApplicationContextInitializer,调用initialize(context);来对IOC容器进行初始化(扩展工作)
也就说之前保存的ApplicationContextInitializer在此时调用了。

遍历所有的Listener调用contextPrepared(context);
通知所有的监听器
至此,IOC容器的上下文配置完毕。

之后就是关闭bootstrapContext.close(context);

然后日志信息

拿到Bean工厂,注册单实例
(项目中的参数会作为组件注册进去)
banner也是IOC容器中的一个组件

所有监听器调用contextLoaded
通知IOC容器已经加载完毕

准备工作完毕

刷新IOC容器
跟随断点进入代码中
    private void refreshContext(ConfigurableApplicationContext context) {
       if (this.registerShutdownHook) {
           shutdownHook.registerApplicationContext(context);
       }
       refresh(context);
   }

注册钩子,接下来进入spring‘的核心源码refresh!
调用IOC容器的refresh

public void refresh() throws BeansException, IllegalStateException {
       synchronized (this.startupShutdownMonitor) {
           StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");

           // Prepare this context for refreshing.
           //为刷新准备上下文。
           prepareRefresh();

           // Tell the subclass to refresh the internal bean factory.
           //告诉子类刷新内部bean工厂。
           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.
               //允许在context子类中对bean工厂进行后处理。
               postProcessBeanFactory(beanFactory);

               StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
               // Invoke factory processors registered as beans in the context.
               //调用在上下文中注册为bean的工厂处理器


               invokeBeanFactoryPostProcessors(beanFactory);

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

               // 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.
               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.
               destroyBeans();

               // Reset 'active' flag.
               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();
               contextRefresh.end();
           }
       }
   }



在源码中有英语注释此处便不再过多赘述,深入源码改日深追!

容器刷新后
afterRefresh(context, applicationArguments);

Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);

监听容器启动花费了多长时间
listener通知项目启动
调用所有的runners
callRunners(context, applicationArguments);

    private void callRunners(ApplicationContext context, ApplicationArguments args) {
        List<Object> runners = new ArrayList<>();
        runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
        runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
        AnnotationAwareOrderComparator.sort(runners);
        for (Object runner : new LinkedHashSet<>(runners)) {
            if (runner instanceof ApplicationRunner) {
                callRunner((ApplicationRunner) runner, args);
            }
            if (runner instanceof CommandLineRunner) {
                callRunner((CommandLineRunner) runner, args);
            }
        }
    }

获取容器中的Runner分别是
ApplicationRunner
CommandLineRunner
合并所有Runner并且按照@Order(优先级)进行排序
遍历所有的Runner调用run方法
异常处理
调用Listener的failed方法

unning方法

  • 通知所有监听器的running方法,如果中间有异常,仍然会调用所有监听器的failed方法

在这里插入图片描述
running方法结束后,返回整个IOC容器。SpringBoot启动结束。

创建结束

posted @ 2022-08-09 16:27  随遇而安==  阅读(160)  评论(0编辑  收藏  举报