• 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事件

    启动源码解析完毕!

  • 相关阅读:
    数据结构(二)(三)栈和队列
    数据结构(一)线性表
    中信卡笔试代码
    Jenkins搭建-简单使用
    python 生成指定两个ip间的所有ip
    形象理解 什么是磁盘碎片
    形象理解软件位宽 32位和64位的区别
    看板娘>_
    Win10一张网卡设置多个ip地址
    VMware ubuntu安装tools灰色?
  • 原文地址:https://www.cnblogs.com/sglx/p/15673240.html
Copyright © 2020-2023  润新知