欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Spring Boot 2.1.1.RELEASE Main方法启动详解二

程序员文章站 2022-05-29 18:34:13
...

二、SpringApplication.run(String... args)方法解析

public ConfigurableApplicationContext run(String... args) {
        // 1.创建一个计时器,并启动计时器
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        ConfigurableApplicationContext context = null;
        Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
        // 2.配置java.awt.headless=true
        configureHeadlessProperty();
        // 3.创建发布事件的监听器,用于向ApplicationListener监听器发布不同消息
        SpringApplicationRunListeners listeners = getRunListeners(args);
        // 4.发布启动事件
        listeners.starting();
        try {
            // 5.封装args参数
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
            // 6.(*)加载环境参数
            ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
            // 7.
            configureIgnoreBeanInfo(environment);
            // 8.创建banner,并打印banner
            Banner printedBanner = printBanner(environment);
            // 9.创建spring容器
            context = createApplicationContext();
            // 10.创建异常报告类
            exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[] { ConfigurableApplicationContext.class }, context);
            // 11.spring容器刷新前处理
            prepareContext(context, environment, listeners, applicationArguments, printedBanner);
            // 12.刷新spring容器
            refreshContext(context);
            // 13.spring容器刷新后处理
            afterRefresh(context, applicationArguments);
            // 14.停止计时器
            stopWatch.stop();
            if (this.logStartupInfo) {
                new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
            }
            // 15.发布spring容器启动完成事件
            listeners.started(context);
            // 16.
            callRunners(context, applicationArguments);
        } catch (Throwable ex) {
            handleRunFailure(context, ex, exceptionReporters, listeners);
            throw new IllegalStateException(ex);
        }

        try {
            listeners.running(context);
        } catch (Throwable ex) {
            handleRunFailure(context, ex, exceptionReporters, null);
            throw new IllegalStateException(ex);
        }
        return context;
}

 

1.1 stopWatch.start()分析

public void start(String taskName) throws IllegalStateException {
        if (this.currentTaskName != null) {
            throw new IllegalStateException("Can't start StopWatch: it's already running");
        }
        this.currentTaskName = taskName;
        // 记录当前时间毫秒值
        this.startTimeMillis = System.currentTimeMillis();
}

 

分析:

  记录当前时间的毫秒值,用于计算启动spring容器时耗时

1.2 配置headless系统变量参数

private void configureHeadlessProperty() {
        System.setProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, System.getProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, Boolean.toString(this.headless)));
}

1.3 创建发布事件的监听器

private SpringApplicationRunListeners getRunListeners(String[] args) {
        Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
        // 1. 加载SpringApplicationRunListener对象
        // 2. 创建SpringApplicationRunListeners对象,统一管理SpringApplicationRunListener对象
        return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
}

 

分析:

  也是通过加载/META-INF/spring.factories中的配置类,创建EventPublishingRunListener时,将所有ApplicationListener交给其管理,并创建了SimpleApplicationEventMulticaster(*)类,它是真正发布事件的类

  • EventPublishingRunListener

1.4 发布启动事件(SimpleApplicationEventMulticaster)

public void starting() {
        this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));
}

1.5 封装args参数

public CommandLineArgs parse(String... args) {
        CommandLineArgs commandLineArgs = new CommandLineArgs();
        // 解析命令行中的参数
        for (String arg : args) {
            // 解析格式为:
            //   --spring.application.name=student
            //   --spring.application.name student
            //   --name
            if (arg.startsWith("--")) {
                String optionText = arg.substring(2, arg.length());
                String optionName;
                String optionValue = null;
                if (optionText.contains("=")) {
                    optionName = optionText.substring(0, optionText.indexOf('='));
                    optionValue = optionText.substring(optionText.indexOf('=')+1, optionText.length());
                } else {
                    optionName = optionText;
                }
                if (optionName.isEmpty() || (optionValue != null && optionValue.isEmpty())) {
                    throw new IllegalArgumentException("Invalid argument syntax: " + arg);
                }
                // 将解析出来的键值对存放到commandLineArgs中的map中
                commandLineArgs.addOptionArg(optionName, optionValue);
            } 
            // 解析格式为:
            //  aaa
            else {
                // 解析非--前缀的命令,添加到commandLineArgs中list中
                commandLineArgs.addNonOptionArg(arg);
            }
        }
        return commandLineArgs;
}

 

分析:解析命令行的参数,并封装到CommandLineArgs对象中

public PropertySource(String name, T source) {
        Assert.hasText(name, "Property source name must contain at least one character");
        Assert.notNull(source, "Property source must not be null");
        // 默认传的名称为:commandLineArgs
        this.name = name;
        // 上一步解析出来的CommandLineArgs对象
        this.source = source;
}

 

分析:封装解析出来的命令行参数CommandLineArgs到PropertySource(父类)->Source(子类)

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

分析:再一次将Source和未解析的args封装到DefaultApplicationArguments中

1.6 加载环境变量

private ConfigurableEnvironment prepareEnvironment(
            SpringApplicationRunListeners listeners,
            ApplicationArguments applicationArguments) {
        // 获取配置环境,根据spring容器类型创建相应的StandardServletEnvironment
        ConfigurableEnvironment environment = getOrCreateEnvironment();
        // 给environment.propertyResolver设置ConversionService
        // 添加命令行参数到environment.propertySource
        // 配置environment.activeProfiles
        configureEnvironment(environment, applicationArguments.getSourceArgs());
        // 发布ApplicationEnvironmentPreparedEvent事件
        listeners.environmentPrepared(environment);
        bindToSpringApplication(environment);
        if (!this.isCustomEnvironment) {
            environment = new EnvironmentConverter(getClassLoader())
                    .convertEnvironmentIfNecessary(environment, deduceEnvironmentClass());
        }
        ConfigurationPropertySources.attach(environment);
        return environment;
}