• SpringBoot 启动流程


    SpringBoot启动流程

    整个启动流程包含,推断 WEB 应用类型,设置初始化器,设置 ApplicationListener 监听器,获取并启动 SpringApplicationRunListener 类,准备 Spring 环境,创建并执行 banner 打印类,创建应用上下文,准备应用上下文,刷新应用上下文,刷新应用上下文之后的调用,执行所有的 Runner 运行器。

    Spring Boot 的入口程序

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

    创建 SpringApplication 对象

    • 初始化主要加载资源类到集合中
    • 推断当前 WEB 应用类型(NONE、SERVLET、REACTIVE)
    • 设置应用上下文初始化器
    • 设置 ApplicationListener 监听器
    • 推断主入口应用类
    // 创建一个新的实例,这个应用上下文将从指定的来源加载 Bean
    public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
        // 初始化资源加载器,默认 null
        this.resourceLoader = resourceLoader;
        // 断言主资源不能为空
        Assert.notNull(primarySources, "PrimarySources must not be null");
        // 初始化主要加载资源类集合并去重
        this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
        // 推断当前 WEB 应用类型,NONE、SERVLET、REACTIVE
        this.webApplicationType = WebApplicationType.deduceFromClasspath();
        // 加载引导程序(2.4.0增加的功能)
        this.bootstrappers = new ArrayList<>(getSpringFactoriesInstances(Bootstrapper.class));
        // 设置初始化器
        setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
        // 设置监听器
        setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
        // 推断主入口应用类
        this.mainApplicationClass = deduceMainApplicationClass();
    }
    

    run 方法启动

    • 创建引导上下文
    • 获取并启动所有 SpringApplicationRunListener 对象
    • 创建默认的应用参数类
    • 准备 Spring 应用环境
    • 创建并执行 banner 打印类
    • 创建应用上下文
    • 准备应用上下文
    • 刷新应用上下文
    public ConfigurableApplicationContext run(String... args) {
        // 创建并启动计时监控类
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        // 创建引导上下文
        DefaultBootstrapContext bootstrapContext = createBootstrapContext();
        ConfigurableApplicationContext context = null;
        // 设置系统属性“java.awt.headless”的值,默认为 true
        configureHeadlessProperty();
        // 创建所有 Spring 运行监听器并发布应用启动事件,
        SpringApplicationRunListeners listeners = getRunListeners(args);
        listeners.starting(bootstrapContext, this.mainApplicationClass);
        try {
            // 初始化默认应用参数类
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
            // 根据运行监听器、引导上下文、应用参数来准备 Spring 环境
            ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
            // 将要忽略的 bean 参数打开
            configureIgnoreBeanInfo(environment);
            // 创建并执行 banner 打印类
            Banner printedBanner = printBanner(environment);
            // 创建应用上下文
            context = createApplicationContext();
            // 设置应用程序启动 步骤
            context.setApplicationStartup(this.applicationStartup);
            // 准备应用上下文
            prepareContext(bootstrapContext, 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);
            // 执行所有的 Runner 运行器
            callRunners(context, applicationArguments);
        }
        catch (Throwable ex) {
            handleRunFailure(context, ex, listeners);
            throw new IllegalStateException(ex);
        }
    
        try {
            // 发布应用上下文就绪事件
            listeners.running(context);
        }
        catch (Throwable ex) {
            handleRunFailure(context, ex, null);
            throw new IllegalStateException(ex);
        }
        return context;
    }
    

    创建引导上下文

    创建并启动引导上下文,2.4.0 之后的版本增加的新功能

    private DefaultBootstrapContext createBootstrapContext() {
        DefaultBootstrapContext bootstrapContext = new DefaultBootstrapContext();
        this.bootstrappers.forEach((initializer) -> initializer.intitialize(bootstrapContext));
        return bootstrapContext;
    }
    

    获取所有 SpringApplicationRunListener 对象并启动

    // 从 META-INF/spring.factories 中获取所有的配置类,并将其封装到 SpringApplicationRunListeners 对象中去,主要创建的对象为 EventPublishingRunListener
    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);
    }
    
    public EventPublishingRunListener(SpringApplication application, String[] args) {
        this.application = application;
        this.args = args;
        this.initialMulticaster = new SimpleApplicationEventMulticaster();
        for (ApplicationListener<?> listener : application.getListeners()) {
            this.initialMulticaster.addApplicationListener(listener);
        }
    }
    
    void starting(ConfigurableBootstrapContext bootstrapContext, Class<?> mainApplicationClass) {
        doWithListeners("spring.boot.application.starting", (listener) -> listener.starting(bootstrapContext),
                        (step) -> {
                            if (mainApplicationClass != null) {
                                step.tag("mainApplicationClass", mainApplicationClass.getName());
                            }
                        });
    }
    
    // 广播事件
    public void starting(ConfigurableBootstrapContext bootstrapContext) {
        this.initialMulticaster
            .multicastEvent(new ApplicationStartingEvent(bootstrapContext, this.application, this.args));
    }
    
    // applicationStartingEvent 是 SpringBoot 框架最早执行的监听器,在该监听器执行 started 方法时,会继续发布事件,主要是基于 Spring 的事件机制
    public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
        ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
        Executor executor = getTaskExecutor();
        for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
            // 如果线程池为空,则同步发送事件,否则异步发送事件
            if (executor != null) {
                executor.execute(() -> invokeListener(listener, event));
            }
            else {
                invokeListener(listener, event);
            }
        }
    }
    
    // 返回与给定事件匹配的监听器
    protected Collection<ApplicationListener<?>> getApplicationListeners(
        ApplicationEvent event, ResolvableType eventType) {
    
        Object source = event.getSource();
        Class<?> sourceType = (source != null ? source.getClass() : null);
        ListenerCacheKey cacheKey = new ListenerCacheKey(eventType, sourceType);
    
        // Potential new retriever to populate
        CachedListenerRetriever newRetriever = null;
    
        // Quick check for existing entry on ConcurrentHashMap
        CachedListenerRetriever existingRetriever = this.retrieverCache.get(cacheKey);
        if (existingRetriever == null) {
            // Caching a new ListenerRetriever if possible
            if (this.beanClassLoader == null ||
                (ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) &&
                 (sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)))) {
                newRetriever = new CachedListenerRetriever();
                existingRetriever = this.retrieverCache.putIfAbsent(cacheKey, newRetriever);
                if (existingRetriever != null) {
                    newRetriever = null;  // no need to populate it in retrieveApplicationListeners
                }
            }
        }
    
        if (existingRetriever != null) {
            Collection<ApplicationListener<?>> result = existingRetriever.getApplicationListeners();
            if (result != null) {
                return result;
            }
            // If result is null, the existing retriever is not fully populated yet by another thread.
            // Proceed like caching wasn't possible for this current local attempt.
        }
    
        return retrieveApplicationListeners(eventType, sourceType, newRetriever);
    }
    

    创建默认的应用参数类

    Source 继承自 SimpleCommandLinePropertySource,用于解析简单的命令行参数

    public DefaultApplicationArguments(String... args) {
        Assert.notNull(args, "Args must not be null");
        this.source = new Source(args);
        this.args = args;
    }
    

    准备 Spring 应用环境

    private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
                                                       DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {
        // Create and configure the environment
        // 创建或者获取应用环境
        ConfigurableEnvironment environment = getOrCreateEnvironment();
        // 配置应用环境
        configureEnvironment(environment, applicationArguments.getSourceArgs());
        ConfigurationPropertySources.attach(environment);
        // listeners 环境准备,广播 ApplicationEnvironmentPreparedEvent
        listeners.environmentPrepared(bootstrapContext, environment);
        // 附加配置源
        DefaultPropertiesPropertySource.moveToEnd(environment);
        // 配置其他激活文件
        configureAdditionalProfiles(environment);
        // 将环境绑定给当前应用程序
        bindToSpringApplication(environment);
        if (!this.isCustomEnvironment) {
            environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment, deduceEnvironmentClass());
        }
        // 配置 propertySource 对它自己的递归依赖
        ConfigurationPropertySources.attach(environment);
        return environment;
    }
    

    创建 banner 打印类并执行

    打印 banner 的详细操作过程

    private Banner printBanner(ConfigurableEnvironment environment) {
        if (this.bannerMode == Banner.Mode.OFF) {
            return null;
        }
        ResourceLoader resourceLoader = (this.resourceLoader != null) ? this.resourceLoader
            : new DefaultResourceLoader(null);
        SpringApplicationBannerPrinter bannerPrinter = new SpringApplicationBannerPrinter(resourceLoader, this.banner);
        if (this.bannerMode == Mode.LOG) {
            return bannerPrinter.print(environment, this.mainApplicationClass, logger);
        }
        return bannerPrinter.print(environment, this.mainApplicationClass, System.out);
    }
    

    创建应用上下文

    根据不同的应用类型初始化不同的山下文应用类

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

    准备应用上下文

    private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
        // 设置应用上下文的 environment
        context.setEnvironment(environment);
        // 应用山下文的后置处理
        postProcessApplicationContext(context);
        // 为上下文应用所有初始化器,执行前面设置的 ApplicationContextInitializer 类
        applyInitializers(context);
        // 触发所有 SpringApplicationRunListener 监听器的 contextPrepared 事件方法。添加所有的事件监听器
        listeners.contextPrepared(context);
        bootstrapContext.close(context);
        // 记录启动日志
        if (this.logStartupInfo) {
            logStartupInfo(context.getParent() == null);
            logStartupProfileInfo(context);
        }
        // Add boot specific singleton beans
        // 注册启动参数bean,将容器指定的参数封装成bean,注入容器
        ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
        beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
        if (printedBanner != null) {
            beanFactory.registerSingleton("springBootBanner", printedBanner);
        }
        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");
        // 将 bean 加载到上下文中
        load(context, sources.toArray(new Object[0]));
    	// 触发所有 SpringApplicationRunListener 监听器的 contextLoaded 事件方法
        listeners.contextLoaded(context);
    }
    
    protected void load(ApplicationContext context, Object[] sources) {
        if (logger.isDebugEnabled()) {
            logger.debug("Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
        }
        BeanDefinitionLoader loader = createBeanDefinitionLoader(getBeanDefinitionRegistry(context), sources);
        if (this.beanNameGenerator != null) {
            loader.setBeanNameGenerator(this.beanNameGenerator);
        }
        if (this.resourceLoader != null) {
            loader.setResourceLoader(this.resourceLoader);
        }
        if (this.environment != null) {
            loader.setEnvironment(this.environment);
        }
        loader.load();
    }
    
    // 后续会使用其将主资源加载到上下文中去,供后续解析使用
    BeanDefinitionLoader(BeanDefinitionRegistry registry, Object... sources) {
        Assert.notNull(registry, "Registry must not be null");
        Assert.notEmpty(sources, "Sources must not be empty");
        this.sources = sources;
        this.annotatedReader = new AnnotatedBeanDefinitionReader(registry);
        this.xmlReader = (XML_ENABLED ? new XmlBeanDefinitionReader(registry) : null);
        this.groovyReader = (isGroovyPresent() ? new GroovyBeanDefinitionReader(registry) : null);
        this.scanner = new ClassPathBeanDefinitionScanner(registry);
        this.scanner.addExcludeFilter(new ClassExcludeFilter(sources));
    }
    
    void load() {
        for (Object source : this.sources) {
            load(source);
        }
    }
    
    private void load(Object source) {
        Assert.notNull(source, "Source must not be null");
        if (source instanceof Class<?>) {
            // Class 的方式加载
            load((Class<?>) source);
            return;
        }
        if (source instanceof Resource) {
            // Resource 资源的方式加载
            load((Resource) source);
            return;
        }
        if (source instanceof Package) {
            load((Package) source);
            return;
        }
        if (source instanceof CharSequence) {
            load((CharSequence) source);
            return;
        }
        throw new IllegalArgumentException("Invalid source type " + source.getClass());
    }
    
    private void load(Class<?> source) {
        if (isGroovyPresent() && GroovyBeanDefinitionSource.class.isAssignableFrom(source)) {
            // Any GroovyLoaders added in beans{} DSL can contribute beans here
            GroovyBeanDefinitionSource loader = BeanUtils.instantiateClass(source, GroovyBeanDefinitionSource.class);
            ((GroovyBeanDefinitionReader) this.groovyReader).beans(loader.getBeans());
        }
        if (isEligible(source)) {
            // 将符合条件的类注册到应用上下文
            this.annotatedReader.register(source);
        }
    }
    
    // 不是常规的闭包并且不是匿名类,即可
    private boolean isEligible(Class<?> type) {
        return !(type.isAnonymousClass() || isGroovyClosure(type) || hasNoConstructors(type));
    }
    

    刷新应用上下文

    最终会调用到 AbstractApplicationContext 抽象类中的 refresh() 方法中去

    refreshContext(context);
    

    刷新后应用上下文调用

    空方法,用于扩展

    执行所有的 Runner 运行器

    执行所有 Runner 执行器,执行所有 ApplicationRunner 和 CommandLineRunner 两种运行器。

    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);
            }
        }
    }
    
  • 相关阅读:
    自定义asp.net mvc Filter 过滤器
    基于委托的C#异步编程的一个小例子 带有回调函数的例子
    ASCII、Unicode和UTF-8编码的区别
    Specification模式的一个不错的示例代码
    codesmith 自动生成C# model 实体模板
    Quartz.NET 实现定时任务调度
    FtpHelper类匿名获取FTP文件
    crc32 根据字符串获取校验值
    机器学习能做什么
    RunHelper,一个为跑步而设计的开源的android app
  • 原文地址:https://www.cnblogs.com/ice-image/p/14549167.html
Copyright © 2020-2023  润新知