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);
	}
}

主要作用是创建MutablePropertySourcesPropertySourcesPropertyResolver

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的环境配置实际值。

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
标签: Spring