SpringBoot启动

发布时间 2023-12-15 15:46:23作者: 小兵要进步

springBoot启动全流程如下所示:

框架初始化,完成相关配置:

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
        this.resourceLoader = resourceLoader;
        Assert.notNull(primarySources, "PrimarySources must not be null");
        this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
        this.webApplicationType = WebApplicationType.deduceFromClasspath();
        setInitializers((Collection) getSpringFactoriesInstances(
                ApplicationContextInitializer.class));
        setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
        this.mainApplicationClass = deduceMainApplicationClass();
    }

 执行run方法:

public ConfigurableApplicationContext run(String... args) {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        ConfigurableApplicationContext context = null;
        Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
        configureHeadlessProperty();
        SpringApplicationRunListeners listeners = getRunListeners(args);
        listeners.starting();
        try {
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(
                    args);
            ConfigurableEnvironment environment = prepareEnvironment(listeners,
                    applicationArguments);
            configureIgnoreBeanInfo(environment);
            Banner printedBanner = printBanner(environment);
            context = createApplicationContext();
            exceptionReporters = getSpringFactoriesInstances(
                    SpringBootExceptionReporter.class,
                    new Class[] { ConfigurableApplicationContext.class }, context);
            prepareContext(context, environment, listeners, applicationArguments,
                    printedBanner);
            refreshContext(context);
            afterRefresh(context, applicationArguments);
            stopWatch.stop();
            if (this.logStartupInfo) {
                new StartupInfoLogger(this.mainApplicationClass)
                        .logStarted(getApplicationLog(), stopWatch);
            }
            listeners.started(context);
            callRunners(context, applicationArguments);
        }
        catch (Throwable ex) {
            handleRunFailure(context, ex, exceptionReporters, listeners);
            throw new IllegalStateException(ex);
        }

        try {
            listeners.running(context);
        }
        catch (Throwable ex) {
            handleRunFailure(context, ex, exceptionReporters, null);
            throw new IllegalStateException(ex);
        }
        return context;
    }

springBoot环境准备:

1 Devtools全局配置  2 测试环境@TestPropertySource注解  3 测试环境properties属性  4 命令行参数  5 SPRING_APPLICATION_JSON属性  6 ServletConfig初始化参数  7 ServletContext初始化参数  8JNDI属性  9 JAVA系统属性  10 操作系统环境变量  11 RandomValuePropertySource随机值属性  12 jar包外的application-{profile}.properties  13 jar包内的application-{profile}.properties  14 jar包外的application.properties  15 14 jar包内的application.properties  16 @PropertySource绑定配置  17 默认属性

private ConfigurableEnvironment prepareEnvironment(
            SpringApplicationRunListeners listeners,
            ApplicationArguments applicationArguments) {
        // Create and configure the environment
        ConfigurableEnvironment environment = getOrCreateEnvironment();
        configureEnvironment(environment, applicationArguments.getSourceArgs());
        listeners.environmentPrepared(environment);
        bindToSpringApplication(environment);
        if (!this.isCustomEnvironment) {
            environment = new EnvironmentConverter(getClassLoader())
                    .convertEnvironmentIfNecessary(environment, deduceEnvironmentClass());
        }
        ConfigurationPropertySources.attach(environment);
        return environment;
    }

环境准备流程图解析:

准备上下文:

private void prepareContext(ConfigurableApplicationContext context,
            ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
            ApplicationArguments applicationArguments, Banner printedBanner) {
        context.setEnvironment(environment);
        postProcessApplicationContext(context);
        //遍历调用Initializer的Initilize方法
        applyInitializers(context);
        //发送ApplicationContextInitializedEvent事件
        listeners.contextPrepared(context);
        if (this.logStartupInfo) {
            logStartupInfo(context.getParent() == null);
            logStartupProfileInfo(context);
        }
        // Add boot specific singleton beans
        ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
        //注册springApplicationArguments
        beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
        if (printedBanner != null) {
            //springBootBanner
            beanFactory.registerSingleton("springBootBanner", printedBanner);
        }
        if (beanFactory instanceof DefaultListableBeanFactory) {
            ((DefaultListableBeanFactory) beanFactory)
                    .setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
        }
        //加载sources
        Set<Object> sources = getAllSources();
        Assert.notEmpty(sources, "Sources must not be empty");
        load(context, sources.toArray(new Object[0]));
        //发送ApplicationPreparedEvent事件
        listeners.contextLoaded(context);
    }

刷新上下文

obtainFreshBeanFactory方法内部通过调用loadBeanDefinitions方法完成了bean定义的加载。

PrepareBeanFactory内部配置工厂的标准上下文特征,例如上下文的ClassLoader和后处理器postProcessors.

postProcessBeanFactory方法允许在bean没有实例化前允许修改应用上下文的内部beanFactory, 允许注册特殊的beanPostProcessors

invokeBeanFactoryPostProcessors方法实例化并调用所有注册的BeanFactoryPostProcessor bean

finishBeanFactoryInitialization方法实例化所有非惰性加载单例bean, 通过defaultListableBeanFactory的preInstantiateSingletons实例化单例bean,具体创建由abstractBeanFactory的getBean方法完成,从这里开始就和spring实例化bean有些类似了。

private void refreshContext(ConfigurableApplicationContext context) {
        refresh(context);
        if (this.registerShutdownHook) {
            try {
                context.registerShutdownHook();
            }
            catch (AccessControlException ex) {
                // Not allowed in some environments.
            }
        }
    }

    protected void refresh(ApplicationContext applicationContext) {
        Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
        ((AbstractApplicationContext) applicationContext).refresh();
    }

    //所属类:ApplicationContext
    public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            //准备刷新此上下文。
            prepareRefresh();
            //告诉子类刷新内部bean工厂
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
            //准备bean工厂以便在此上下文中使用。
            prepareBeanFactory(beanFactory);
            try {
                //允许在上下文子类中对bean工厂进行后处理。
                //在标准初始化之后修改应用程序上下文的内部bean工厂。
                //所有的bean定义都将被加载,但还没有任何bean被实例化。这允许在某些ApplicationContext实现中注册特殊的BeanPostProcessors
                postProcessBeanFactory(beanFactory);
                //调用在上下文中注册为bean的工厂处理器(beanFactoryPostProcessor)
                invokeBeanFactoryPostProcessors(beanFactory);
                //注册拦截bean创建的bean处理器。
                registerBeanPostProcessors(beanFactory);
                //初始化此上下文的消息源。
                initMessageSource();
                //初始化此上下文的事件多播。
                initApplicationEventMulticaster();
                //初始化特定上下文子类中的其他特殊bean。
                onRefresh();
                //检查侦听器bean并注册它们。
                registerListeners();
                //实例化所有剩余的(非惰性init)singleton。
                finishBeanFactoryInitialization(beanFactory);
                //最后一步:发布相应的事件。
                finishRefresh();
            }
            catch (BeansException ex) {
                if (logger.isWarnEnabled()) {
                    logger.warn("Exception encountered during context initialization - " +
                            "cancelling refresh attempt: " + ex);
                }
                //销毁已创建的singleton以避免挂起资源。
                destroyBeans();
                cancelRefresh(ex);
                throw ex;
            }
            finally {
                //重置Spring核心中的常见内省缓存,因为我们可能再也不需要单例bean的元数据了。。。
                resetCommonCaches();
            }
        }
    }