docs/Spring全家桶/SpringBoot源码解析/SpringBoot启动流程(二):准备运行环境.md
ģǼĽSpringApplication#run(String...)
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 ̡
stopWatchʱһʼspringboot ʹstopWatchʵȻStopWatch#start()ʱܣûɶ˵ģǸʱ springboot ʱ־еʱʱõģ
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ģʽôǸɶģʽأ˵ģʽϵͳȱʾ豸̻ģʽһ㶼¹ġ
һǻȡмԼڼһЩ״̬룺
// ȡҲǴ 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 õм£
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(...)ȶĵ·濴˾Ͳظˡ
Ĵ£
// װ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;
}
Կֻص㽲
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()õIJSystem.getProperties()õIJservlet``servletContext``servletConfig.Ǽſụ̂Ҳ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лȡˡ
ˣķ͵ˡ
Ҫһspring.beaninfo.ignoreǷBeanInfo``Դ֪ĬֵtrueоõIJ࣬Ͳˡ
bannerbannerӡģ
Banner printedBanner = printBanner(environment);
ҲԼ bannerϽ̳һѣdemo Ͳṩˡ
banner springboot ̹ϵͲˣСֻ˽ôüɡ
ˣƪľ͵ˣƪǼ
ԭӣhttps://my.oschina.net/funcy/blog/4882417߸ˮƽд֮ӭָԭףҵתϵȨҵתע