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

二、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;
}

 

posted @ 2019-08-16 16:53  张界  阅读(615)  评论(0编辑  收藏  举报