SpringBoot加载配置文件源码解析
阿里云国内75折 回扣 微信号:monov8 |
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6 |
1、SpringApplication
public ConfigurableApplicationContext run(String... args) {
...
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
//StandardServletEnvironment#1.1.1
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
ConfigurableApplicationContext context = createApplicationContext();
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
refreshContext(context);
afterRefresh(context, applicationArguments);
listeners.started(context);
callRunners(context, applicationArguments);
listeners.running(context);
return context;
}
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments) {
ConfigurableEnvironment environment = getOrCreateEnvironment();//实例化StandardServletEnvironment
configureEnvironment(environment, applicationArguments.getSourceArgs());
listeners.environmentPrepared(environment);
...
return environment;
}
1.1、解析应用参数Program Arguments & 环境属性Environment Variable
由核心类StandardServletEnvironment
及其父类AbstractEnvironment完成解析&持有 Program Arguments、Environment Variable配置值。
protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
configurePropertySources(environment, args);
configureProfiles(environment, args);
}
protected void configurePropertySources(ConfigurableEnvironment environment, String[] args) {
MutablePropertySources sources = environment.getPropertySources();
...
sources.addFirst(new SimpleCommandLinePropertySource(args));// #3
}
StandardServletEnvironment父类AbstractEnvironment属性MutablePropertySources持有应用参数|运行参数args【CommandLineArgs】。
protected void configureProfiles(ConfigurableEnvironment environment, String[] args) {
environment.getActiveProfiles(); //AbstractEnvironment#getActiveProfiles
Set<String> profiles = new LinkedHashSet<>(this.additionalProfiles);
profiles.addAll(Arrays.asList(environment.getActiveProfiles()));
environment.setActiveProfiles(StringUtils.toStringArray(profiles));
}
1.2、解析应用配置文件信息SpringApplicationRunListeners
public void environmentPrepared(ConfigurableEnvironment environment) {
for (SpringApplicationRunListener listener : this.listeners) {
listener.environmentPrepared(environment);//EventPublishingRunListener#environmentPrepared
}
}
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
//eventTypeApplicationEnvironmentPreparedEvent
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
Executor executor = getTaskExecutor();
for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
if (executor != null) {
executor.execute(() -> invokeListener(listener, event));
}
else {
invokeListener(listener, event);
}
}
}
1.2.1、EventPublishingRunListener
2、AbstractEnvironment
public abstract class AbstractEnvironment implements ConfigurableEnvironment {
private final MutablePropertySources propertySources = new MutablePropertySources();
private final ConfigurablePropertyResolver propertyResolver =
new PropertySourcesPropertyResolver(this.propertySources);
public static final String ACTIVE_PROFILES_PROPERTY_NAME = "spring.profiles.active";
public AbstractEnvironment() {
customizePropertySources(this.propertySources);//StandardServletEnvironment#customizePropertySources
}
public String[] getActiveProfiles() {
return StringUtils.toStringArray(doGetActiveProfiles());
}
protected Set<String> doGetActiveProfiles() {
synchronized (this.activeProfiles) {
if (this.activeProfiles.isEmpty()) {
String profiles = getProperty(ACTIVE_PROFILES_PROPERTY_NAME);
if (StringUtils.hasText(profiles)) {
setActiveProfiles(StringUtils.commaDelimitedListToStringArray(
StringUtils.trimAllWhitespace(profiles)));
}
}
return this.activeProfiles;
}
}
public String getProperty(String key) {
return this.propertyResolver.getProperty(key);
}
}
主要作用是创建MutablePropertySources
、PropertySourcesPropertyResolver
。
2.1、StandardServletEnvironment
Spring中的StandardServletEnvironment将由基于servlet的web应用程序使用所有基于servlet的web相关ApplicationContext类将会初始化一个StandardServletEnvironment实例。
StandardServletEnvironment实例化过程
- MutablePropertySources实例化。
- PropertySourcesPropertyResolver实例化。
- 获取到应用全部的
系统属性以及环境变量属性
。
2.1.1、StandardServletEnvironment实例化
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();
}
}
StandardServletEnvironment的实例化会调用其抽象类AbstractEnvironment
的构造方法在AbstractEnvironment构造方法中调用子类StandardServletEnvironment#customizePropertySources
方法。
2.1.2、StandardServletEnvironment类信息
public class StandardServletEnvironment extends StandardEnvironment implements ConfigurableWebEnvironment {
/** servletContext初始化参数属性源名 */
public static final String SERVLET_CONTEXT_PROPERTY_SOURCE_NAME = "servletContextInitParams";
/** ServletConfig初始化参数属性源名 */
public static final String SERVLET_CONFIG_PROPERTY_SOURCE_NAME = "servletConfigInitParams";
/** JNDI属性源名 */
public static final String JNDI_PROPERTY_SOURCE_NAME = "jndiProperties";
@Override
protected void customizePropertySources(MutablePropertySources propertySources) {
propertySources.addLast(new StubPropertySource(SERVLET_CONFIG_PROPERTY_SOURCE_NAME));
propertySources.addLast(new StubPropertySource(SERVLET_CONTEXT_PROPERTY_SOURCE_NAME));
if (JndiLocatorDelegate.isDefaultJndiEnvironmentAvailable()) {
propertySources.addLast(new JndiPropertySource(JNDI_PROPERTY_SOURCE_NAME));
}
super.customizePropertySources(propertySources);//StandardEnvironment#customizePropertySources
}
@Override
public void initPropertySources(@Nullable ServletContext servletContext, @Nullable ServletConfig servletConfig) {
WebApplicationContextUtils.initServletPropertySources(getPropertySources(), servletContext, servletConfig);
}
}
2.2、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) {
propertySources.addLast(
new PropertiesPropertySource(SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME, getSystemProperties()));
propertySources.addLast(
new SystemEnvironmentPropertySource(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, getSystemEnvironment()));
}
}
- getSystemProperties()其实就是通过
(Map) System.getProperties()
获取系统属性包括用户自定义的JVM的参数【-D】。 - getSystemEnvironment()通过
(Map) System.getenv()
获取应用环境变量属性例如spring.profiles.active=dev
等。
此时并没有解析配置文件的配置信息
3、ConfigurableApplicationContext
protected ConfigurableApplicationContext createApplicationContext() {
Class<?> contextClass = this.applicationContextClass;
switch (this.webApplicationType) {
case SERVLET://AnnotationConfigServletWebServerApplicationContext
contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
break;
case REACTIVE://AnnotationConfigReactiveWebServerApplicationContext
contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
break;
default://AnnotationConfigApplicationContext
contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
}
return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
}
4、SimpleCommandLinePropertySource
public SimpleCommandLinePropertySource(String... args) {
super(new SimpleCommandLineArgsParser().parse(args));
}
4.1、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("=")) {
optionName = optionText.substring(0, optionText.indexOf('='));
optionValue = optionText.substring(optionText.indexOf('=')+1, optionText.length());
}
else {
optionName = optionText;
}
commandLineArgs.addOptionArg(optionName, optionValue);
}
else {
commandLineArgs.addNonOptionArg(arg);
}
}
return commandLineArgs;
}
- CommandLineArgs#addOptionArgMap集合类型的存储结构。
- CommandLineArgs#addNonOptionArgList集合类型的存储结构。
如果Program Arguments项中配置项是通过"–"符号设置则以Map集合类型的结构存储否则List集合类型的结构存储。
Program Arguments --mq.client=huawei --mq.name=lisi mq.age=10 mq.addr=北京
5、PropertySourcesPropertyResolver
public class PropertySourcesPropertyResolver extends AbstractPropertyResolver {
private final PropertySources propertySources;//MutablePropertySources
protected <T> T getProperty(String key, Class<T> targetValueType, boolean resolveNestedPlaceholders) {
if (this.propertySources != null) {
for (PropertySource<?> propertySource : this.propertySources) {
Object value = propertySource.getProperty(key);
if (value != null) {
if (resolveNestedPlaceholders && value instanceof String) {
value = resolveNestedPlaceholders((String) value);
}
logKeyFound(key, propertySource, value);
return convertValueIfNecessary(value, targetValueType);
}
}
}
return null;
}
}
PropertySourcesPropertyResolver中PropertySources即为MutablePropertySources其包含servletContextInitParams、servletConfigInitParams、jndiProperties、systemEnvironment、systemProperties五部分。最终通过systemEnvironment获取到spring.profiles.active
的环境配置实际值。