Springboot启动流程分析

一、构造器初始化

    public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
        return run(new Class<?>[] { primarySource }, args);
    }
    
    public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
        //构造方式初始化
        return new SpringApplication(primarySources).run(args);
    }
    public SpringApplication(Class<?>... primarySources) {
        this(null, primarySources);
    }
    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));
        //推断应用类型reactive,servlet
        this.webApplicationType = WebApplicationType.deduceFromClasspath();
        //初始化classpath下 META-INF/spring.factories中配置的ApplicationContextInitializer
        //主要通过构造器反射创建
        setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
        //初始化classpath下所有配置的 ApplicationListener(META-INF/spring.factories)
        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<>();
        //java.awt.headless是J2SE的一种模式用于在缺少显示屏、键盘或者鼠标时的系统配置
        // 很多监控工具如jconsole 需要将该值设置为true,系统变量默认为true
        configureHeadlessProperty();
        //从META-INF/spring.factories中获取监听器  SpringApplicationRunListeners
        //也是通过构造器实例化,但并没有放入IOC容器
        SpringApplicationRunListeners listeners = getRunListeners(args);
        //遍历回调SpringApplicationRunListeners的starting方法
        listeners.starting();
        try {
            //封装命令行参数
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
            //构造应用上下文环境,完成后回调SpringApplicationRunListeners的environmentPrepared方法
            ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
            //判断是否后续处理需要忽略的Bean
            configureIgnoreBeanInfo(environment);
            //打印banner
            Banner printedBanner = printBanner(environment);
            //根据是否web环境创建相应的IOC容器
            context = createApplicationContext();
            //实例化SpringBootExceptionReporter,用来支持报告关于启动的错误
            exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
                    new Class<?>[] { ConfigurableApplicationContext.class }, context);
            //完成启动类的加载
            //准备上下文环境,将environment设置到IOC容器中
            //执行applyInitializers,遍历回调ApplicationContextInitializer的initialize方法
            //遍历回调SpringApplicationRunListeners的contextPrepared方法
            //遍历回调SpringApplicationRunListeners的contextLoaded方法
            prepareContext(context, environment, listeners, applicationArguments, printedBanner);
            //完成容器的初始化,bean的生命周期
            refreshContext(context);
            //空方法,子类扩展实现
            afterRefresh(context, applicationArguments);
            //启动完成,时间截止
            stopWatch.stop();
            if (this.logStartupInfo) {
                new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
            }
            //发布容器启动完成事件
            listeners.started(context);
            //从IOC容器获取所有的ApplicationRunner(先调用)和CommandLinedRunner进行回调
            callRunners(context, applicationArguments);
        }
        catch (Throwable ex) {
            handleRunFailure(context, ex, exceptionReporters, listeners);
            throw new IllegalStateException(ex);
        }

        try {
            //执行配置文件中的监听器的running方法
            listeners.running(context);
        }
        catch (Throwable ex) {
            handleRunFailure(context, ex, exceptionReporters, null);
            throw new IllegalStateException(ex);
        }
        return context;
    }

1、记录启动时间

2、SpringApplicationRunListeners监听器实例化

3、调用监听器的starting方法

void starting() {
        for (SpringApplicationRunListener listener : this.listeners) {
            listener.starting();
        }
    }
    
    //EventPublishingRunListener
    public void starting() {
        //关键代码,这里是创建application启动事件:ApplicationStartingEvent发布启动事件
        this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));
    }
    
    public void multicastEvent(ApplicationEvent event) {
        multicastEvent(event, resolveDefaultEventType(event));
    }
    
    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 {
                //执行listener的onApplicationEvent方法,这里有一个关键的listener,BackgroundPreinitializer
                invokeListener(listener, event);
            }
        }
    }
    
    protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
        ErrorHandler errorHandler = getErrorHandler();
        if (errorHandler != null) {
            try {
                doInvokeListener(listener, event);
            }
            catch (Throwable err) {
                errorHandler.handleError(err);
            }
        }
        else {
            doInvokeListener(listener, event);
        }
    }
    
    private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
        try {
            listener.onApplicationEvent(event);
        }
        catch (ClassCastException ex) {
            ···
        }
    }

BackgroundPreinitializer

//BackgroundPreinitializer
    public void onApplicationEvent(SpringApplicationEvent event) {
        if (!Boolean.getBoolean(IGNORE_BACKGROUNDPREINITIALIZER_PROPERTY_NAME)
                && event instanceof ApplicationStartingEvent && multipleProcessors()
                && preinitializationStarted.compareAndSet(false, true)) {
            //执行此方法    
            performPreinitialization();
        }
        if ((event instanceof ApplicationReadyEvent || event instanceof ApplicationFailedEvent)
                && preinitializationStarted.get()) {
            try {
                preinitializationComplete.await();
            }
            catch (InterruptedException ex) {
                Thread.currentThread().interrupt();
            }
        }
    }
    private void performPreinitialization() {
        try {
            Thread thread = new Thread(new Runnable() {
                //初始化一些转换器
                @Override
                public void run() {
                    runSafely(new ConversionServiceInitializer());
                    runSafely(new ValidationInitializer());
                    runSafely(new MessageConverterInitializer());
                    runSafely(new JacksonInitializer());
                    runSafely(new CharsetInitializer());
                    preinitializationComplete.countDown();
                }

                public void runSafely(Runnable runnable) {
                    try {
                        runnable.run();
                    }
                    catch (Throwable ex) {
                        // Ignore
                    }
                }

            }, "background-preinit");
            thread.start();
        }
        catch (Exception ex) {
            preinitializationComplete.countDown();
        }
    }

4、封装入参

5、构建应用上下文环境

        private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
            ApplicationArguments applicationArguments) {
        //创建并配置相应的环境,获取对应的ConfigurableEnvironment
        ConfigurableEnvironment environment = getOrCreateEnvironment();
        //根据用户配置,配置 environment系统环境
        configureEnvironment(environment, applicationArguments.getSourceArgs());
        ConfigurationPropertySources.attach(environment);
        //发布监听事件,调用的是ConfigFileApplicationListener的onApplicationEvent方法
        //这个就是加载项目配置文件的监听器
        listeners.environmentPrepared(environment);
        bindToSpringApplication(environment);
        if (!this.isCustomEnvironment) {
            environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
                    deduceEnvironmentClass());
        }
        ConfigurationPropertySources.attach(environment);
        return environment;
    }
    
    //根据环境创建对应ConfigurableEnvironment
    private ConfigurableEnvironment getOrCreateEnvironment() {
        if (this.environment != null) {
            return this.environment;
        }
        switch (this.webApplicationType) {
        case SERVLET://Web程序
            return new StandardServletEnvironment();
        case REACTIVE://响应式web环境
            return new StandardReactiveWebEnvironment();
        default://普通程序
            return new StandardEnvironment();
        }
    }
    protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
        if (this.addConversionService) {
            ConversionService conversionService = ApplicationConversionService.getSharedInstance();
            environment.setConversionService((ConfigurableConversionService) conversionService);
        }
        // 将main 函数的args封装成 SimpleCommandLinePropertySource 加入environment中。
        configurePropertySources(environment, args);
        // 激活相应的配置文件
        configureProfiles(environment, args);
    }

6、配置需要忽略的bean

7、打印Banner

8、根据应用类型创建相应的容器

9、实例化启动报告

9、容器预启动,这里也是加载启动类的地方,之前已经分析过了

    private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
            SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
        //环境配置
        context.setEnvironment(environment);
        //执行容器后置处理
        postProcessApplicationContext(context);
        // 执行容器中ApplicationContextInitializer实现类的initialize方法
        // 包括spring.factories和通过三种方式自定义的
        applyInitializers(context);
        //向各个监听器发送容器已经准备好的事件
        listeners.contextPrepared(context);
        if (this.logStartupInfo) {
            logStartupInfo(context.getParent() == null);
            logStartupProfileInfo(context);
        }
        ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
        //将main函数中的args参数封装成单例Bean,放进进容器
        beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
        if (printedBanner != null) {
            //将 printedBanner 封装成单例,注册进容器
            beanFactory.registerSingleton("springBootBanner", printedBanner);
        }
        if (beanFactory instanceof DefaultListableBeanFactory) {
            ((DefaultListableBeanFactory) beanFactory)
                    .setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
        }
        if (this.lazyInitialization) {
            context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
        }
        //拿到启动类
        Set<Object> sources = getAllSources();
        Assert.notEmpty(sources, "Sources must not be empty");
        //sources就是启动类,这里面把启动类注册成了一个beanDefinition
        load(context, sources.toArray(new Object[0]));
        //发布容器已加载事件
        listeners.contextLoaded(context);
    }
        //这里默认不执行任何逻辑,因为beanNameGenerator和resourceLoader默认为空。springBoot预留的扩展处理方式,配置上下文的 bean 生成器及资源加载器
    protected void postProcessApplicationContext(ConfigurableApplicationContext context) {
        //如果设置了是beanName生成器,注册到Spring容器中
        if (this.beanNameGenerator != null) {
            context.getBeanFactory().registerSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR,
                    this.beanNameGenerator);
        }
        // 如果设置了资源加载器,设置到Spring容器中
        if (this.resourceLoader != null) {
            if (context instanceof GenericApplicationContext) {
                ((GenericApplicationContext) context).setResourceLoader(this.resourceLoader);
            }
            if (context instanceof DefaultResourceLoader) {
                ((DefaultResourceLoader) context).setClassLoader(this.resourceLoader.getClassLoader());
            }
        }
        if (this.addConversionService) {
            context.getBeanFactory().setConversionService(ApplicationConversionService.getSharedInstance());
        }
    }

10、完成IOC容器的加载,这里也是tomcat启动地方,之前也已经分析过了,其他的就是spring源码里面的refresh方法了

11、定义了一个空方法,留给子类扩展

12、容器启动完成,记录截至时间

13、发布容器初始化完成事件

14、调用ApplicationRunner(先调用)和CommandLinedRunner的实现类的run方法,可以自己实现这两个接口,会在容器初始化完成后被调用

15、执行监听器的running方法,发布的是一个ApplicationReadyEvent事件

启动源码解析完毕!

原文地址:https://www.cnblogs.com/sglx/p/15673240.html