springboot加载配置文件源码解析

Spring是如何加载application.properties、application.yml、application-dev.yml、application-pro.yml等等的配置文件的?先后顺序是怎么样的。

1.看SpringApplication的run方法的源码

/**
	 * Run the Spring application, creating and refreshing a new
	 * {@link ApplicationContext}.
	 * @param args the application arguments (usually passed from a Java main method)
	 * @return a running {@link ApplicationContext}
	 */
	public ConfigurableApplicationContext run(String... args) {
		StopWatch stopWatch = new StopWatch();
		stopWatch.start();
		ConfigurableApplicationContext context = null;
		Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
		configureHeadlessProperty();
		SpringApplicationRunListeners listeners = getRunListeners(args);
		listeners.starting();
		try {
			ApplicationArguments applicationArguments = new DefaultApplicationArguments(
					args);
			// 2.准备环境从这里进去
			ConfigurableEnvironment environment = prepareEnvironment(listeners,
					applicationArguments);
			configureIgnoreBeanInfo(environment);
			Banner printedBanner = printBanner(environment);
			context = createApplicationContext();
			exceptionReporters = getSpringFactoriesInstances(
					SpringBootExceptionReporter.class,
					new Class[] { ConfigurableApplicationContext.class }, context);
			prepareContext(context, environment, listeners, applicationArguments,
					printedBanner);
			refreshContext(context);
			afterRefresh(context, applicationArguments);
			stopWatch.stop();
			if (this.logStartupInfo) {
				new StartupInfoLogger(this.mainApplicationClass)
						.logStarted(getApplicationLog(), stopWatch);
			}
			listeners.started(context);
			callRunners(context, applicationArguments);
		}
		
	}

2.准备环境

private ConfigurableEnvironment prepareEnvironment(
			SpringApplicationRunListeners listeners,
			ApplicationArguments applicationArguments) {
		// Create and configure the environment
		ConfigurableEnvironment environment = getOrCreateEnvironment();
		configureEnvironment(environment, applicationArguments.getSourceArgs());
		// 从这个方法一直跟进去到org.springframework.boot.context.config.ConfigFileApplicationListener#onApplicationEvent
		listeners.environmentPrepared(environment);
		bindToSpringApplication(environment);
		if (!this.isCustomEnvironment) {
			environment = new EnvironmentConverter(getClassLoader())
					.convertEnvironmentIfNecessary(environment, deduceEnvironmentClass());
		}
		ConfigurationPropertySources.attach(environment);
		return environment;
	}
  1. 到这个地方org.springframework.boot.context.config.ConfigFileApplicationListener#onApplicationEvent
@Override
	public void onApplicationEvent(ApplicationEvent event) {
		if (event instanceof ApplicationEnvironmentPreparedEvent) {
			// 从这里进去,一直跟到org.springframework.boot.context.config.ConfigFileApplicationListener.Loader#load()这个方法
			onApplicationEnvironmentPreparedEvent(
					(ApplicationEnvironmentPreparedEvent) event);
		}
		if (event instanceof ApplicationPreparedEvent) {
			onApplicationPreparedEvent(event);
		}
	}
  1. org.springframework.boot.context.config.ConfigFileApplicationListener.Loader#load()
public void load() {
			this.profiles = new LinkedList<>();
			this.processedProfiles = new LinkedList<>();
			this.activatedProfiles = false;
			this.loaded = new LinkedHashMap<>();
			initializeProfiles();
			while (!this.profiles.isEmpty()) {
				Profile profile = this.profiles.poll();
				if (profile != null && !profile.isDefaultProfile()) {
					addProfileToEnvironment(profile.getName());
				}
				load(profile, this::getPositiveProfileFilter,
						addToLoaded(MutablePropertySources::addLast, false));
				this.processedProfiles.add(profile);
			}
			resetEnvironmentProfiles(this.processedProfiles);
			load(null, this::getNegativeProfileFilter,
					addToLoaded(MutablePropertySources::addFirst, true));
			addLoadedPropertySources();
		}
private void load(Profile profile, DocumentFilterFactory filterFactory,
				DocumentConsumer consumer) {
			// 获取到所有的配置文件地址 (file:./config/,file:./,classpath:/config/,classpath:/)
	getSearchLocations().forEach((location) -> {
		boolean isFolder = location.endsWith("/");
		Set<String> names = isFolder ? getSearchNames() : NO_SEARCH_NAMES;
		// 对这些配置文件地址一一进行加载
		names.forEach(
				(name) -> load(location, name, profile, filterFactory, consumer));
	});
}
private void load(String location, String name, Profile profile,
				DocumentFilterFactory filterFactory, DocumentConsumer consumer) {
			if (!StringUtils.hasText(name)) {
				for (PropertySourceLoader loader : this.propertySourceLoaders) {
					if (canLoadFileExtension(loader, location)) {
						load(loader, location, profile,
								filterFactory.getDocumentFilter(profile), consumer);
						return;
					}
				}
			}
			Set<String> processed = new HashSet<>();
			// 获取配置文件解析的类 (PropertiesPropertySourceLoader, YamlPropertySourceLoader)
			for (PropertySourceLoader loader : this.propertySourceLoaders) {
				// 解析文件的后缀(.xml, .properties, .yaml, .yml)
				for (String fileExtension : loader.getFileExtensions()) {
					if (processed.add(fileExtension)) {
						loadForFileExtension(loader, location + name, "." + fileExtension,
								profile, filterFactory, consumer);
					}
				}
			}
		}
private void load(PropertySourceLoader loader, String location, Profile profile,
				DocumentFilter filter, DocumentConsumer consumer) {
	try {
		// 获取对应路径下的配置文件(classpath:/application.yml)
		Resource resource = this.resourceLoader.getResource(location);
		// 判断是否存在,一般运行后会存在于target/classes/application.yml
		if (resource == null || !resource.exists()) {
			if (this.logger.isTraceEnabled()) {
				StringBuilder description = getDescription(
						"Skipped missing config ", location, resource, profile);
				this.logger.trace(description);
			}
			return;
		}
		if (!StringUtils.hasText(
				StringUtils.getFilenameExtension(resource.getFilename()))) {
			if (this.logger.isTraceEnabled()) {
				StringBuilder description = getDescription(
						"Skipped empty config extension ", location, resource,
						profile);
				this.logger.trace(description);
			}
			return;
		}
		String name = "applicationConfig: [" + location + "]";
		// 加载对应的配置文件
		List<Document> documents = loadDocuments(loader, name, resource);
		if (CollectionUtils.isEmpty(documents)) {
			if (this.logger.isTraceEnabled()) {
				StringBuilder description = getDescription(
						"Skipped unloaded config ", location, resource, profile);
				this.logger.trace(description);
			}
			return;
		}
		List<Document> loaded = new ArrayList<>();
		for (Document document : documents) {
			if (filter.match(document)) {
				// 将对应的激活的配置文件的信息写入到Deque<Profile>双向队列中
				addActiveProfiles(document.getActiveProfiles());
				addIncludedProfiles(document.getIncludeProfiles());
				loaded.add(document);
			}
		}
		Collections.reverse(loaded);
		if (!loaded.isEmpty()) {
			loaded.forEach((document) -> consumer.accept(profile, document));
			if (this.logger.isDebugEnabled()) {
				StringBuilder description = getDescription("Loaded config file ",
						location, resource, profile);
				this.logger.debug(description);
			}
		}
	}
	catch (Exception ex) {
		throw new IllegalStateException("Failed to load property "
				+ "source from location '" + location + "'", ex);
	}
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值