Back to Javatutorial

SpringBoot启动流程(二):准备运行环境

docs/Spring全家桶/SpringBoot源码解析/SpringBoot启动流程(二):准备运行环境.md

1.0.014.6 KB
Original Source

ģǼĽSpringApplication#run(String...)

3.springbootУSpringApplication#run(String...)

£

public ConfigurableApplicationContext run(String... args) {
    // 1\.  StopWatch ʵʵǸʱͳspringbootʱ
    StopWatch stopWatch = new StopWatch();
    stopWatch.start();
    // ׼յApplicationContextԼһ쳣
    ConfigurableApplicationContext context = null;
    Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
    // 2\. һϵͳԣjava.awt.headlessjava.awt.headlessģʽϵͳһģʽ
    // ϵͳȱʾ豸̻Щ¿ʹøģʽ
    configureHeadlessProperty();
    // 3\. ȡҲǴ META-INF/spring.factories лȡ
    SpringApplicationRunListeners listeners = getRunListeners(args);
    // starting()״runʱáڷdzڵijʼ׼ʱ֮ǰ
    // 4\. ¼
    listeners.starting();
    try {
        // װIJ
        ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
        // 5\. 
        ConfigurableEnvironment environment 
                = prepareEnvironment(listeners, applicationArguments);
        // 6\.  spring.beaninfo.ignore򽫸ýϵͳ
        configureIgnoreBeanInfo(environment);
        // 7\. banner
        Banner printedBanner = printBanner(environment);
        // 8\. applicationContext
        context = createApplicationContext();
        // 󱨸Զصӿ
        exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
                new Class[] { ConfigurableApplicationContext.class }, context);
        // 9\. ׼ģһϵеֵ
        prepareContext(context, environment, listeners, applicationArguments, printedBanner);
        // 10\.  AbstractApplicationContext.refreshspring
        refreshContext(context);
        // 11\. ˢºĴ
        afterRefresh(context, applicationArguments);
        stopWatch.stop();
        if (this.logStartupInfo) {
            new StartupInfoLogger(this.mainApplicationClass)
                .logStarted(getApplicationLog(), stopWatch);
        }
        // 12\. ¼
        listeners.started(context);
        // 13\.  runnerʵ ApplicationRunnerCommandLineRunner Ľӿ
        callRunners(context, applicationArguments);
    }
    catch (Throwable ex) {
        handleRunFailure(context, ex, exceptionReporters, listeners);
        throw new IllegalStateException(ex);
    }
    try {
        // 14\. ¼
        listeners.running(context);
    }
    catch (Throwable ex) {
        handleRunFailure(context, ex, exceptionReporters, null);
        throw new IllegalStateException(ex);
    }
    return context;
}

£

ص 13 ̡

3.1stopWatchʱ

һʼspringboot ʹstopWatchʵȻStopWatch#start()ʱܣûɶ˵ģǸʱ springboot ʱ־еʱʱõģ

3.2 java.awt.headlessֵ

SpringApplication#configureHeadlessPropertyش£

public class SpringApplication {

    private static final String SYSTEM_PROPERTY_JAVA_AWT_HEADLESS = "java.awt.headless";

    ...

    private boolean headless = true;

    public void setHeadless(boolean headless) {
        this.headless = headless;
    }
    ...

    private void configureHeadlessProperty() {
        //  java.awt.headless ֵõϵͳ
        System.setProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS,
                System.getProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, 
                Boolean.toString(this.headless)));
    }
    ...
}

ǽjava.awt.headlessֵõϵͳótrueʾjava.awt.headlessģʽôǸɶģʽأ˵ģʽϵͳȱʾ豸̻ģʽһ㶼¹ġ

3.3 ȡм

һǻȡмԼڼһЩ״̬룺

// ȡҲǴ META-INF/spring.factories лȡ
SpringApplicationRunListeners listeners = getRunListeners(args);

SpringApplication#getRunListeners

public class SpringApplication {
    ...

    private SpringApplicationRunListeners getRunListeners(String[] args) {
        Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
        return new SpringApplicationRunListeners(logger,
                // ȻǴMETA-INF/spring.factories лȡkey  SpringApplicationRunListener
                getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
    }
    ...
}

ԿSpringApplicationRunListenerȻǴMETA-INF/spring.factoriesлȡSpringApplicationRunListenerǸɶأ룺

public interface SpringApplicationRunListener {

    /**
     * ״runʱáڷdzڵijʼ
     */
    default void starting() {
    }

    /**
     * ׼ûEnvironmentɣڴApplicationContext֮ǰá
     */
    default void environmentPrepared(ConfigurableEnvironment environment) {
    }

    /**
     * ڴ͹ApplicationContext֮󣬵ڼ֮ǰá
     */
    default void contextPrepared(ConfigurableApplicationContext context) {
    }

    /**
     * ApplicationContextѼصˢ֮ǰá
     */
    default void contextLoaded(ConfigurableApplicationContext context) {
    }

    /**
     * ApplicationContextˢ£Ӧó
     * δCommandLineRunnersApplicationRunners
     */
    default void started(ConfigurableApplicationContext context) {
    }

    /**
     * з֮ǰã
     * ˢApplicationContextCommandLineRunnersApplicationRunner
     */
    default void running(ConfigurableApplicationContext context) {
    }

    /**
     * Ӧóʱʧʱá
     */
    default void failed(ConfigurableApplicationContext context, Throwable exception) {
    }
}

SpringApplicationRunListenerһӿڣһϵеķ springboot ̣˵Ѿĵϸ壬Ҫ springboot еijһЩ飬ͿʵSpringApplicationRunListenerȻдӦķ

ͨԣ springboot õм£

3.4 мlisteners.starting()

صSpringApplication#run(java.lang.String...)ȡм󣬻starting()¼

// ȡ
SpringApplicationRunListeners listeners = getRunListeners(args);
// starting()״runʱáڷdzڵijʼ׼ʱ֮ǰ
listeners.starting();

SpringApplicationRunListeners#starting

void starting() {
    for (SpringApplicationRunListener listener : this.listeners) {
        listener.starting();
    }
}

Կνķ¼DZеļһstarting()ˣthis.listenersȡемˣSpringApplicationRunListener``environmentPrepared(...)``contextPrepared(...)ȶĵ·濴˾Ͳظˡ

3.5 ׼ʱ

Ĵ£

// װIJ
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// 
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);

SpringApplication#prepareEnvironment

private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
        ApplicationArguments applicationArguments) {
    // ȡ򴴽
    ConfigurableEnvironment environment = getOrCreateEnvironment();
    // ʱ
    configureEnvironment(environment, applicationArguments.getSourceArgs());
    ConfigurationPropertySources.attach(environment);
    //  SpringApplicationRunListener  environmentPrepared 
    // EnvironmentɣڴApplicationContext֮ǰ
    listeners.environmentPrepared(environment);
    // Ӧð
    bindToSpringApplication(environment);
    if (!this.isCustomEnvironment) {
        environment = new EnvironmentConverter(getClassLoader())
                .convertEnvironmentIfNecessary(environment, deduceEnvironmentClass());
    }
    ConfigurationPropertySources.attach(environment);
    return environment;
}

Կֻ׼ص㽲

1. ȡ򴴽Environment

ֱӽSpringApplication#getOrCreateEnvironment

private ConfigurableEnvironment getOrCreateEnvironment() {
    if (this.environment != null) {
        return this.environment;
    }
    switch (this.webApplicationType) {
    case SERVLET:
        return new StandardServletEnvironment();
    case REACTIVE:
        return new StandardReactiveWebEnvironment();
    default:
        return new StandardEnvironment();
    }
}

ӴǸӦӦEnvironmentʵǰӦSERVLETֱӿStandardServletEnvironmentδġ

֪ java УʱȵøĹ췽ֱӽAbstractEnvironment


public abstract class AbstractEnvironment implements ConfigurableEnvironment {

    ...

    public AbstractEnvironment() {
        customizePropertySources(this.propertySources);
    }

    ...
}

AbstractEnvironmentĹ췽УcustomizePropertySources()``StandardServletEnvironmentʵ֣

public class StandardServletEnvironment extends StandardEnvironment 
        implements ConfigurableWebEnvironment {
    public static final String SERVLET_CONTEXT_PROPERTY_SOURCE_NAME = "servletContextInitParams";
    public static final String SERVLET_CONFIG_PROPERTY_SOURCE_NAME = "servletConfigInitParams";
    public static final String JNDI_PROPERTY_SOURCE_NAME = "jndiProperties";

    @Override
    protected void customizePropertySources(MutablePropertySources propertySources) {
        //  servletConfigInitParams
        propertySources.addLast(new StubPropertySource(SERVLET_CONFIG_PROPERTY_SOURCE_NAME));
        //  servletContextInitParams
        propertySources.addLast(new StubPropertySource(SERVLET_CONTEXT_PROPERTY_SOURCE_NAME));
        if (JndiLocatorDelegate.isDefaultJndiEnvironmentAvailable()) {
            propertySources.addLast(new JndiPropertySource(JNDI_PROPERTY_SOURCE_NAME));
        }
        // øķ
        super.customizePropertySources(propertySources);
    }

    @Override
    public void initPropertySources(@Nullable ServletContext servletContext, 
            @Nullable ServletConfig servletConfig) {
        // 滻õ servletContextInitParams Ϊ servletContext
        // 滻õ servletConfigInitParams Ϊ servletConfig
        WebApplicationContextUtils.initServletPropertySources(
                getPropertySources(), servletContext, servletConfig);
    }

}

ԿStandardServletEnvironment``customizePropertySources()ֻ˼ servlet صIJȻȥøĹ췽ˣǼStandardEnvironment

ƺûʲôǼ׷٣Ĺ췽

public class StandardEnvironment extends AbstractEnvironment {

    /** ϵͳ */
    public static final String SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME = "systemEnvironment";

    /** ϵͳ */
    public static final String SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME = "systemProperties";

    @Override
    protected void customizePropertySources(MutablePropertySources propertySources) {
        // ȡϵͳԣõ System.getenv()
        propertySources.addLast(new PropertiesPropertySource(
                SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME, getSystemProperties()));
        // ȡϵͳõ System.getProperties()
        propertySources.addLast(new SystemEnvironmentPropertySource(
                SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, getSystemEnvironment()));
    }

}

ԿStandardEnvironment``customizePropertySources()ҪǽϵͳϵͳӵEnvironmentСʵϣEnvironmentаϵͳ뻷صIJҲṩһЩgetterԺܷػȡЩ

ǾˣStandardServletEnvironmentаݣ

  • ϵͳԣƽʱSystem.getenv()õIJ
  • ϵͳƽʱSystem.getProperties()õIJ
  • servlet``servletContext``servletConfig.

2. û

Ǽſụ̂ҲSpringApplication#configureEnvironment

protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
    if (this.addConversionService) {
        // תת StringתNumberIntegerתEnum
        ConversionService conversionService = ApplicationConversionService.getSharedInstance();
        environment.setConversionService((ConfigurableConversionService) conversionService);
    }
    // ӵ environment 
    configurePropertySources(environment, args);
    //  ActiveProfiles ֵ
    configureProfiles(environment, args);
}

벻࣬ؼ㶼ڴעˣҪ΢SpringApplication#configurePropertySources

protected void configurePropertySources(ConfigurableEnvironment environment, String[] args) {
    MutablePropertySources sources = environment.getPropertySources();
    // ĬԣָĬԣ
    if (this.defaultProperties != null && !this.defaultProperties.isEmpty()) {
        sources.addLast(new MapPropertySource("defaultProperties", this.defaultProperties));
    }
    if (this.addCommandLineProperties && args.length > 0) {
        String name = CommandLinePropertySource.COMMAND_LINE_PROPERTY_SOURCE_NAME;
        if (sources.contains(name)) {
            PropertySource<?> source = sources.get(name);
            CompositePropertySource composite = new CompositePropertySource(name);
            composite.addPropertySource(
                    // ʱIJ
                    new SimpleCommandLinePropertySource("springApplicationCommandLineArgs", args));
            composite.addPropertySource(source);
            sources.replace(name, composite);
        }
        else {
            sources.addFirst(new SimpleCommandLinePropertySource(args));
        }
    }
}

ԴIJнSimpleCommandLinePropertySource

public class SimpleCommandLinePropertySource 
        extends CommandLinePropertySource<CommandLineArgs> {

    public SimpleCommandLinePropertySource(String... args) {
        super(new SimpleCommandLineArgsParser().parse(args));
    }
    ...
}

սķSimpleCommandLineArgsParser#parse

public class SimpleCommandLineArgsParser {
    public CommandLineArgs parse(String... args) {
        CommandLineArgs commandLineArgs = new CommandLineArgs();
        for (String arg : args) {
            if (arg.startsWith("--")) {
                String optionText = arg.substring(2, arg.length());
                String optionName;
                String optionValue = null;
                if (optionText.contains("=")) {
                    // -- ͷҰ = IJᱻ key/value
                    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.addOptionArg(optionName, optionValue);
            }
            else {
                commandLineArgs.addNonOptionArg(arg);
            }
        }
        return commandLineArgs;
    }

    ...
}

DZȽϼ򵥵ģַĴѡ

springboot ɶýأ spring Ŀʱǿָ

java -jar xxx.jar --a1=aaa --b1=bbb

ȻǾͨ@Value("${a1}")ȡؼԿspringboot Ѵ--a1=aaa``--b1=bbb``a1/aaa``b1/bbbֵԵʽ浽EnvironmentҪõʱͿɺܷشEnvironmentлȡˡ

ˣ׼ķ͵ˡ

3.6 ϵͳ

Ҫһspring.beaninfo.ignoreǷBeanInfo``Դ֪ĬֵtrueоõIJ࣬Ͳˡ

3.7 ӡbanner

bannerӡģ

Banner printedBanner = printBanner(environment);

ҲԼ bannerϽ̳һѣdemo Ͳṩˡ

banner springboot ̹ϵ󣬾ͲˣСֻ˽ôüɡ

ˣƪľ͵ˣƪǼ


ԭӣhttps://my.oschina.net/funcy/blog/4882417߸ˮƽд֮ӭָԭףҵתϵ߻Ȩҵתע