原理解析

Spring Boot 启动过程

1、示例

@SpringBootApplication
public class MainApplication {

    public static void main(String[] args) {
        SpringApplication.run(MainApplication.class, args);
    }
}

2、SpringApplication 类

public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
    return run(new Class<?>[] { primarySource }, args);
}

public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
    //创建SpringApplication -> 运行SpringApplication
    return new SpringApplication(primarySources).run(args);
}

 

创建 SpringApplication

1、构造器

public SpringApplication(Class<?>... primarySources) {
    this(null, primarySources);
}

2、保存信息到 Spring Boot

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
    //保存资源加载器
    this.resourceLoader = resourceLoader;
    //断言primarySources(主配置类)不为null,否则发送错误信息
    Assert.notNull(primarySources, "PrimarySources must not be null");
    //保存主配置类
    this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
    //判断Web应用类型
    this.webApplicationType = WebApplicationType.deduceFromClasspath();
    //获取初始启动器,若spring.factories存在BootstrapRegistryInitializer,则创建实例
    this.bootstrapRegistryInitializers = new ArrayList<>(getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
    //获取初始化器,若spring.factories存在ApplicationContextInitializer,则创建实例
    setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
    //获取监听器,若spring.factories存在ApplicationListener,则创建实例
    setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
    //获取主程序类
    this.mainApplicationClass = deduceMainApplicationClass();
}

(1)判定当前应用的类型

static WebApplicationType deduceFromClasspath() {
    //判断是否为响应式编程
    if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
        && !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
        return WebApplicationType.REACTIVE;
    }
    for (String className : SERVLET_INDICATOR_CLASSES) {
        if (!ClassUtils.isPresent(className, null)) {
            return WebApplicationType.NONE;
        }
    }
    //返回Servlet
    return WebApplicationType.SERVLET;
}

(2)获取初始启动器 

private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
    return getSpringFactoriesInstances(type, new Class<?>[] {});
}

private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
    //获取类加载器
    ClassLoader classLoader = getClassLoader();
    //SpringFactoriesLoader加载META-INF/spring.factories,默认扫描当前系统中所有包的META-INF/spring.factories
    Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
    List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
    AnnotationAwareOrderComparator.sort(instances);
    return instances;
}

(3)获取主程序类

private Class<?> deduceMainApplicationClass() {
    try {
        //获取堆栈
        StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
        //遍历堆栈
        for (StackTraceElement stackTraceElement : stackTrace) {
            //若存在main方法,则为主程序类
            if ("main".equals(stackTraceElement.getMethodName())) {
                return Class.forName(stackTraceElement.getClassName());
            }
        }
    }
    catch (ClassNotFoundException ex) {
        // Swallow and continue
    }
    return null;
}

 

运行 SpringApplication

//args:命令行参数
public ConfigurableApplicationContext run(String... args) {
    //获取应用启动时间(纳秒)
    long startTime = System.nanoTime();
    //创建引导上下文环境
    DefaultBootstrapContext bootstrapContext = createBootstrapContext();
    ConfigurableApplicationContext context = null;
    //让当前应用进入headless模式
    configureHeadlessProperty();
    //获取所有RunListener(运行监听器),方便所有Listener进行事件感知
    SpringApplicationRunListeners listeners = getRunListeners(args);
    //遍历listeners调用starting方法,通知项目正在starting
    listeners.starting(bootstrapContext, this.mainApplicationClass);
    try {
        //保存命令行参数
        ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
        //准备环境
        ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
        //配置忽略的Bean信息
        configureIgnoreBeanInfo(environment);
        //打印Banner
        Banner printedBanner = printBanner(environment);
        //创建IOC容器
        context = createApplicationContext();
        context.setApplicationStartup(this.applicationStartup);
        //准备IOC容器的基本信息(ApplicationContext)
        prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
        //刷新IOC容器
        refreshContext(context);
        afterRefresh(context, applicationArguments);
        //统计启动所需时间
        Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
        if (this.logStartupInfo) {
            new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup);
        }
        //所有监听器调用started(),通知所有监听器启动完成
        listeners.started(context, timeTakenToStartup);
        //呼叫所有Runner
        callRunners(context, applicationArguments);
    }
    //捕获以上执行流程抛出异常
    catch (Throwable ex) {
        handleRunFailure(context, ex, listeners);
        throw new IllegalStateException(ex);
    }
    try {
        Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);
        //调用所有监听器ready方法,通知所有监听器进入就绪状态
        listeners.ready(context, timeTakenToReady);
    }
    //捕获ready抛出异常
    catch (Throwable ex) {
        handleRunFailure(context, ex, null);
        throw new IllegalStateException(ex);
    }
    return context;
}

1、创建引导上下文环境

private DefaultBootstrapContext createBootstrapContext() {
    //创建默认引导上下文环境
    DefaultBootstrapContext bootstrapContext = new DefaultBootstrapContext();
    //遍历在创建SpringApplication时获取的bootstrapRegistryInitializers,调用其intitialize(),完成对引导启动器上下文环境设置
    this.bootstrapRegistryInitializers.forEach((initializer) -> initializer.initialize(bootstrapContext));
    return bootstrapContext;
}

2、让当前应用进入headless模式

private void configureHeadlessProperty() {
    System.setProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS,
                       System.getProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, Boolean.toString(this.headless)));
}
private static final String SYSTEM_PROPERTY_JAVA_AWT_HEADLESS = "java.awt.headless";

3、获取所有运行监听器

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

4、遍历 listeners 调用 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());
                        }
                    });
}
private void doWithListeners(String stepName, Consumer<SpringApplicationRunListener> listenerAction,
                             Consumer<StartupStep> stepAction) {
    StartupStep step = this.applicationStartup.start(stepName);
    //listenerAction事件信息,即starting
    this.listeners.forEach(listenerAction);
    if (stepAction != null) {
        stepAction.accept(step);
    }
    step.end();
}

5、准备环境

private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
                                                   DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {
    //返回已存在的环境信息对象,或创建基础环境信息对象
    ConfigurableEnvironment environment = getOrCreateEnvironment();
    //获取命令行参数,配置环境信息对象
    configureEnvironment(environment, applicationArguments.getSourceArgs());
    //绑定环境信息
    ConfigurationPropertySources.attach(environment);
    //监听器调用environmentPrepared(),通知所有监听器当前环境准备完成
    listeners.environmentPrepared(bootstrapContext, environment);
    DefaultPropertiesPropertySource.moveToEnd(environment);
    Assert.state(!environment.containsProperty("spring.main.environment-prefix"),
                 "Environment prefix cannot be set via properties.");
    bindToSpringApplication(environment);
    if (!this.isCustomEnvironment) {
        EnvironmentConverter environmentConverter = new EnvironmentConverter(getClassLoader());
        environment = environmentConverter.convertEnvironmentIfNecessary(environment, deduceEnvironmentClass());
    }
    ConfigurationPropertySources.attach(environment);
    return environment;
}

(1)返回已存在的环境信息对象,或创建基础环境信息对象

private ConfigurableEnvironment getOrCreateEnvironment() {
    if (this.environment != null) {
        return this.environment;
    }
    switch (this.webApplicationType) {
        case SERVLET:
            return new ApplicationServletEnvironment();
        case REACTIVE:
            return new ApplicationReactiveWebEnvironment();
        default:
            return new ApplicationEnvironment();
    }
}

(2)配置环境信息对象

protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
    if (this.addConversionService) {
        //使用类型转换器
        environment.setConversionService(new ApplicationConversionService());
    }
    //读取所有配置源的配置属性值
    configurePropertySources(environment, args);
    //激活Profiles环境内容
    configureProfiles(environment, args);
}

(3)监听器调用 environmentPrepared(),通知所有监听器当前环境准备完成

void environmentPrepared(ConfigurableBootstrapContext bootstrapContext, ConfigurableEnvironment environment) {
    //遍历所有listener调用environmentPrepared
    doWithListeners("spring.boot.application.environment-prepared",
                    (listener) -> listener.environmentPrepared(bootstrapContext, environment));
}
private void doWithListeners(String stepName, Consumer<SpringApplicationRunListener> listenerAction) {
    doWithListeners(stepName, listenerAction, null);
}
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();
}

6、创建 IOC 容器

protected ConfigurableApplicationContext createApplicationContext() {
    //根据项目类型创建容器
    return this.applicationContextFactory.create(this.webApplicationType);
}

7、准备 IOC 容器的基本信息

private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context,
                            ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
                            ApplicationArguments applicationArguments, Banner printedBanner) {
    //保存环境信息到IOC容器
    context.setEnvironment(environment);
    //IOC容器的后置处理
    postProcessApplicationContext(context);
    //应用初始化器
    applyInitializers(context);
    //监听器准备上下文环境
    listeners.contextPrepared(context);
    //引导关闭上下文
    bootstrapContext.close(context);
    if (this.logStartupInfo) {
        logStartupInfo(context.getParent() == null);
        logStartupProfileInfo(context);
    }
    //获取Bean工厂
    ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
    //注册命令行参数组件:springApplicationArguments
    beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
    if (printedBanner != null) {
        //注册Banner组件:springBootBanner
        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());
    }
    context.addBeanFactoryPostProcessor(new PropertySourceOrderingBeanFactoryPostProcessor(context));
    // 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);
}

(1)应用初始化器

@SuppressWarnings({ "rawtypes", "unchecked" })
protected void applyInitializers(ConfigurableApplicationContext context) {
    //遍历所有ApplicationContextInitializer,调用initialize(),对IOC容器进行初始化扩展功能
    for (ApplicationContextInitializer initializer : getInitializers()) {
        Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(),
                                                                        ApplicationContextInitializer.class);
        Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
        initializer.initialize(context);
    }
}

(2)监听器准备上下文环境

void contextPrepared(ConfigurableApplicationContext context) {
    //遍历所有listener,调用contextPrepared;EventPublishRunListenr:通知所有的监听器contextPrepared
    doWithListeners("spring.boot.application.context-prepared", (listener) -> listener.contextPrepared(context));
}
private void doWithListeners(String stepName, Consumer<SpringApplicationRunListener> listenerAction) {
    doWithListeners(stepName, listenerAction, null);
}
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();
}

(3)监听器加载上下文环境

void contextLoaded(ConfigurableApplicationContext context) {
    //遍历所有监听器,调用contextLoaded,通知所有监听器contextLoaded
    doWithListeners("spring.boot.application.context-loaded", (listener) -> listener.contextLoaded(context));
}
private void doWithListeners(String stepName, Consumer<SpringApplicationRunListener> listenerAction) {
    doWithListeners(stepName, listenerAction, null);
}
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();
}

8、刷新 IOC 容器

private void refreshContext(ConfigurableApplicationContext context) {
    if (this.registerShutdownHook) {
        shutdownHook.registerApplicationContext(context);
    }
    refresh(context);
}
protected void refresh(ConfigurableApplicationContext applicationContext) {
    applicationContext.refresh();
}

(1)创建容器中的所有组件

finishBeanFactoryInitialization(beanFactory);

9、呼叫所有Runner

private void callRunners(ApplicationContext context, ApplicationArguments args) {
    //保存所有Runner
    List<Object> runners = new ArrayList<>();
    //从IOC容器中获取所有ApplicationRunner
    runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
    //从IOC容器中获取所有CommandLineRunner
    runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
    //合并所有Runner,且按照@Order进行排序
    AnnotationAwareOrderComparator.sort(runners);
    //遍历所有Runner
    for (Object runner : new LinkedHashSet<>(runners)) {
        if (runner instanceof ApplicationRunner) {
            callRunner((ApplicationRunner) runner, args);
        }
        if (runner instanceof CommandLineRunner) {
            callRunner((CommandLineRunner) runner, args);
        }
    }
}

(1)调用 run 方法

private void callRunner(ApplicationRunner runner, ApplicationArguments args) {
    try {
        (runner).run(args);
    }
    catch (Exception ex) {
        throw new IllegalStateException("Failed to execute ApplicationRunner", ex);
    }
}

10、处理抛出的异常

private void handleRunFailure(ConfigurableApplicationContext context, Throwable exception,
                              SpringApplicationRunListeners listeners) {
    try {
        try {
            handleExitCode(context, exception);
            if (listeners != null) {
                //调用Listener的failed方法
                listeners.failed(context, exception);
            }
        }
        finally {
            reportFailure(getExceptionReporters(context), exception);
            if (context != null) {
                context.close();
                shutdownHook.deregisterFailedApplicationContext(context);
            }
        }
    }
    catch (Exception ex) {
        logger.warn("Unable to close ApplicationContext", ex);
    }
    ReflectionUtils.rethrowRuntimeException(exception);
}

 

核心组件

1、需要 spring.factories 配置

(1)ApplicationContextInitializer

(2)ApplicationListener

(3)SpringApplicationRunListener

2、合并 Runner

(1)ApplicationRunner

(2)CommandLineRunner

3、全流程

(1)ApplicationListener:onApplicationEvent()

(2)SpringApplicationRunListener:starting()

(3)ApplicationListener:onApplicationEvent()

(4)SpringApplicationRunListener:environmentPrepared()

(5)ApplicationContextInitializer:initialize()

(6)ApplicationListener:onApplicationEvent()

(7)SpringApplicationRunListener:contextPrepared

(8)ApplicationListener:onApplicationEvent()

(9)SpringApplicationRunListener:contextLoaded()

(10)ApplicationListener:onApplicationEvent() * 4

(11)ApplicationRunner + CommandLineRunner:根据 @Order 排序,调用 run()

(12)ApplicationListener:onApplicationEvent() * 2

(13)SpringApplicationRunListener:ready()

posted @   半条咸鱼  阅读(67)  评论(0编辑  收藏  举报
(评论功能已被禁用)
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
点击右上角即可分享
微信分享提示