zoukankan      html  css  js  c++  java
  • SpringBoot启动过程

    研究SpringBoot的自动装配,同时也想弄明白它的启动流程,然后就有了这篇随笔。

    SpringBoot的启动一般都是从main方法开始,这也是它的第一步

    //SpringBoot注解,用于启动的
    @SpringBootApplication
    public class DemoApplication {
    
        public static void main(String[] args) {
          //启动类静态的run方法
            SpringApplication.run(DemoApplication.class, args);
        }
    
    }

    第二步就是通过构造方法在创建SpringApplication对象时,会初始化对象的值

    public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
            this.sources = new LinkedHashSet();
      //定义标志输出模式 
            this.bannerMode = Mode.CONSOLE;
            this.logStartupInfo = true;
            this.addCommandLineProperties = true;
            this.addConversionService = true;
            this.headless = true;
            this.registerShutdownHook = true;
            this.additionalProfiles = Collections.emptySet();
            this.isCustomEnvironment = false;
            this.lazyInitialization = false;
            this.applicationContextFactory = ApplicationContextFactory.DEFAULT;
            this.applicationStartup = ApplicationStartup.DEFAULT;
            this.resourceLoader = resourceLoader;
            Assert.notNull(primarySources, "PrimarySources must not be null");
            this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));
           //通过调用deduceFromClasspath方法判断web应用是什么类型的
            this.webApplicationType = WebApplicationType.deduceFromClasspath();
           //将启动注册初始化类通过工厂类得到实例放到ArrayList列表
            this.bootstrapRegistryInitializers = new ArrayList(this.getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
           //将应用上下文初始化类通过工厂类得到实例进行初始化
            this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
           //ApplicationListener监听器类通过工厂类得到实例放进监听器
            this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
          //得到main方法类实例
            this.mainApplicationClass = this.deduceMainApplicationClass();
        }

    第三步就是会执行对应的run方法,run方法源码为:

     public ConfigurableApplicationContext run(String... args) {
       //获取启动时的时间毫秒数
            long startTime = System.nanoTime();
       //创建一个启动上下文容器
            DefaultBootstrapContext bootstrapContext = this.createBootstrapContext();
            ConfigurableApplicationContext context = null;
       //设置Headless模式属性,Headless模式模式代表当缺少外设依赖时使用此模式
            this.configureHeadlessProperty();
       //创建监听器,监听器开始启动
            SpringApplicationRunListeners listeners = this.getRunListeners(args);
            listeners.starting(bootstrapContext, this.mainApplicationClass);
    
            try {
              //创建一个应用属性对象
                ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
              //创建应用的上下文环境,从配置的application.properties等配置文件中读取
                ConfigurableEnvironment environment = this.prepareEnvironment(listeners, bootstrapContext, applicationArguments);
              //用来忽略所有自定义的BeanInfo类的搜索
                this.configureIgnoreBeanInfo(environment);
              //打印banner标志
                Banner printedBanner = this.printBanner(environment);
              //创建应用程序上下文
                context = this.createApplicationContext();
              //设置应用启动器
                context.setApplicationStartup(this.applicationStartup);
              //对bean,属性,标志进行初始化生成和处理
                this.prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
              //进行上下文刷新工作,如对系统关闭周期钩子重置内容等等
                this.refreshContext(context);
                this.afterRefresh(context, applicationArguments);
              //得到启动时长
                Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
              //告诉那个应用启动用了多少秒
                if (this.logStartupInfo) {
                    (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), timeTakenToStartup);
                }
                //启动完成通知
                listeners.started(context, timeTakenToStartup);
              //如果有ApplicationRunner或者CommandLineRunner类型的bean,就会触发调用
                this.callRunners(context, applicationArguments);
            } catch (Throwable var12) {
                this.handleRunFailure(context, var12, listeners);
                throw new IllegalStateException(var12);
            }
    
            try {
                Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);
                listeners.ready(context, timeTakenToReady);
                return context;
            } catch (Throwable var11) {
                this.handleRunFailure(context, var11, (SpringApplicationRunListeners)null);
                throw new IllegalStateException(var11);
            }
        }
    

    在上面的方法中有这一行代码  ConfigurableEnvironment environment = this.prepareEnvironment(listeners, bootstrapContext, applicationArguments);  这一行代码涉及到了环境处理,属性设置等等。针对涉及到的this.prepareEnvironment(listeners, bootstrapContext, applicationArguments);方法进行解析

    private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {
      //根据web应用类型选择响应的应用容器环境
            ConfigurableEnvironment environment = this.getOrCreateEnvironment();
      //进行环境参数配置,但是此方法先去查看是否需要转换服务,再有条件地进行环境参数配置
            this.configureEnvironment((ConfigurableEnvironment)environment, applicationArguments.getSourceArgs());
      //通过判断环境中的是否含有onfigurationProperties的属性进行不同的处理
            ConfigurationPropertySources.attach((Environment)environment);
      //环境初始化,加载生效的profile等资源
            listeners.environmentPrepared(bootstrapContext, (ConfigurableEnvironment)environment);
      //配置属性中添加defaultProperties默认配置
            DefaultPropertiesPropertySource.moveToEnd((ConfigurableEnvironment)environment);
      //判断环境属性中是否包含spring.main.environment-prefix键,如果包含的话,则会报出异常,异常内容第二个参数
            Assert.state(!((ConfigurableEnvironment)environment).containsProperty("spring.main.environment-prefix"), "Environment prefix cannot be set via properties.");
      //将配置属性与各种组件进行绑定
            this.bindToSpringApplication((ConfigurableEnvironment)environment);
      //判断是否需要进行容器类型转换
            if (!this.isCustomEnvironment) {
                environment = this.convertEnvironment((ConfigurableEnvironment)environment);
            }
    //通过判断环境中的是否含有onfigurationProperties的属性进行不同的处理
            ConfigurationPropertySources.attach((Environment)environment);
            return (ConfigurableEnvironment)environment;
        }

    在上面run方法的源码中有这行代码this.prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);,查看这个方法源码

     private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
            context.setEnvironment(environment);
       //应用程序对自定义的加载器进行加载
            this.postProcessApplicationContext(context);
       //初始化上下文
            this.applyInitializers(context);
       //调用监听器
            listeners.contextPr epared(context);
       //往下追的话也是调用各种监听器
            bootstrapContext.close(context);
       //日志输出,输出了一行JDK信息和进程号,以及生效的profile模式内容
            if (this.logStartupInfo) {
                this.logStartupInfo(context.getParent() == null);
                this.logStartupProfileInfo(context);
            }
    //创建一个bean工厂
            ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
       //利用工厂进行注册
            beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
            if (printedBanner != null) {
                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());
            }
    //加载资源
            Set<Object> sources = this.getAllSources();
            Assert.notEmpty(sources, "Sources must not be empty");
            this.load(context, sources.toArray(new Object[0]));
            listeners.contextLoaded(context);
        }
    生于忧患,死于安乐
  • 相关阅读:
    从无到有构建vue实战项目(二)
    从无到有构建vue实战项目(一)
    windows下nginx的安装和使用
    系统全局环境变量设置
    100个常用的linux命令
    Linux常用系统信息查看命令
    linux下搜索find命令拾遗
    linux基础优化
    linux系统基础文件属性
    正则awk和查看文件行数
  • 原文地址:https://www.cnblogs.com/songlove/p/15647502.html
Copyright © 2011-2022 走看看