springboot啟動-enviroment環境加載


springboot 創建環境

SpringApplication 准備環境

private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
			ApplicationArguments applicationArguments) {
	// Create and configure the environment
	ConfigurableEnvironment environment = getOrCreateEnvironment(); //默認應用是SERVLET,new StandardServletEnvironment();
	configureEnvironment(environment, applicationArguments.getSourceArgs());// enviroment和args進行綁定,如果配置文件不是defaultProperty,這個步驟實際上是個空操作
	ConfigurationPropertySources.attach(environment);//給enviroment的source中增加key為configurationProperties的SpringConfigurationPropertySources對象
	listeners.environmentPrepared(environment);//主要步驟,查找active的profile
	bindToSpringApplication(environment);//與啟動類進行綁定
	if (!this.isCustomEnvironment) {
		environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
				deduceEnvironmentClass());
	}
	ConfigurationPropertySources.attach(environment);
	return environment;
}

void environmentPrepared(ConfigurableEnvironment environment) {
	for (SpringApplicationRunListener listener : this.listeners) {
		listener.environmentPrepared(environment);
	}
}

EventPublishingRunListener 執行監聽事件

private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
	try {
		listener.onApplicationEvent(event);
	}catch (ClassCastException ex) {
		
	}
}

ConfigFileApplicationListener 類進行環境加載操作

主要是判斷那些profile是active的,並對其配置文件進行解析

1.解析環境

private void onApplicationEnvironmentPreparedEvent(ApplicationEnvironmentPreparedEvent event) {
	List<EnvironmentPostProcessor> postProcessors = loadPostProcessors();
	postProcessors.add(this);//增加自身實例
	AnnotationAwareOrderComparator.sort(postProcessors);
	for (EnvironmentPostProcessor postProcessor : postProcessors) {
		postProcessor.postProcessEnvironment(event.getEnvironment(), event.getSpringApplication());
	}
}

2.loadPostProcessors()方法獲取spring.factories中EnvironmentPostProcessor 類配置

# Environment Post Processors
org.springframework.boot.env.EnvironmentPostProcessor=\
org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor,\
org.springframework.boot.env.SpringApplicationJsonEnvironmentPostProcessor,\
org.springframework.boot.env.SystemEnvironmentPropertySourceEnvironmentPostProcessor,\
org.springframework.boot.reactor.DebugAgentEnvironmentPostProcessor

3.ConfigFileApplicationListener類的postProcessEnvironment方法

       加載配置文件,以yml文件進行分析;

protected void addPropertySources(ConfigurableEnvironment environment, ResourceLoader resourceLoader) {
	RandomValuePropertySource.addToEnvironment(environment);
	new Loader(environment, resourceLoader).load();
}

Loader(ConfigurableEnvironment environment, ResourceLoader resourceLoader) {
	this.environment = environment;
	this.placeholdersResolver = new PropertySourcesPlaceholdersResolver(this.environment);
	this.resourceLoader = (resourceLoader != null) ? resourceLoader : new DefaultResourceLoader();
	this.propertySourceLoaders = SpringFactoriesLoader.loadFactories(PropertySourceLoader.class,
			getClass().getClassLoader());//獲取實例類,如下
}



spring.factories中PropertySourceLoader.class 配置的類
yml文件解析的解析類和property文件的解析類

# PropertySource Loaders
org.springframework.boot.env.PropertySourceLoader=\
org.springframework.boot.env.PropertiesPropertySourceLoader,\
org.springframework.boot.env.YamlPropertySourceLoader

4.加載配置的yml或propertis文件的詳細過程

萬惡的load方法

       以YML文件解析為例,總共涉及到六個load方法,每個方法都處理不同的業務

ConfigFileApplicationListener類的總的加載方法

void load() {
	FilteredPropertySource.apply(this.environment, DEFAULT_PROPERTIES, LOAD_FILTERED_PROPERTY,
	(defaultProperties) -> {
		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 (isDefaultProfile(profile)) {
				addProfileToEnvironment(profile.getName());
			}
			load(profile, this::getPositiveProfileFilter,
					addToLoaded(MutablePropertySources::addLast, false));
			this.processedProfiles.add(profile);
		}
		load(null, this::getNegativeProfileFilter, addToLoaded(MutablePropertySources::addFirst, true));
		addLoadedPropertySources();
		applyActiveProfiles(defaultProperties);
	});
}

根據路徑加載配置文件,load()方法

  1. getSearchLocations()方法獲取配置文件掃描路徑。默認是DEFAULT_SEARCH_LOCATIONS。

  2. 配置文件的名稱names 默認是 DEFAULT_NAMES 也即是application。

private static final String DEFAULT_SEARCH_LOCATIONS = "classpath:/,classpath:/config/,file:./,file:./config/";

private static final String DEFAULT_NAMES = "application";

private void load(Profile profile, DocumentFilterFactory filterFactory, DocumentConsumer consumer) {
	getSearchLocations().forEach((location) -> {
		boolean isFolder = location.endsWith("/");
		Set<String> names = isFolder ? getSearchNames() : NO_SEARCH_NAMES;
		names.forEach((name) -> load(location, name, profile, filterFactory, consumer));//遍歷路徑查找配置文件
	});
}

根據路徑,查找yml和properites的配置文件

       根據路徑 + 文件名稱 + 后綴進行配置文件查找

private void load(String location, String name, Profile profile, DocumentFilterFactory filterFactory,
		DocumentConsumer consumer) {
	Set<String> processed = new HashSet<>();
	for (PropertySourceLoader loader : this.propertySourceLoaders) {
		for (String fileExtension : loader.getFileExtensions()) {
			if (processed.add(fileExtension)) {
				loadForFileExtension(loader, location + name, "." + fileExtension, profile, filterFactory,
						consumer);
			}
		}
	}
}
//PropertiesPropertySourceLoader  properties加載器的后綴
public String[] getFileExtensions() {
	return new String[] { "properties", "xml" };
}

//YamlPropertySourceLoader yml加載器的后綴
@Override
public String[] getFileExtensions() {
	return new String[] { "yml", "yaml" };
}

private void loadForFileExtension(PropertySourceLoader loader, String prefix, String fileExtension,
				Profile profile, DocumentFilterFactory filterFactory, DocumentConsumer consumer) {
	//省略部分代碼。。。。。。。。。。。。。。。。。
	load(loader, prefix + fileExtension, profile, profileFilter, consumer); //這里的load方法是加載資源的方法,具體過程如下
}

加載資源,配置數據解析

       判斷是否為激活的YML配置文件,並且獲取YML文件的配置信息

private void load(PropertySourceLoader loader, String location, Profile profile, DocumentFilter filter,
				DocumentConsumer consumer) {
	try {
		Resource resource = this.resourceLoader.getResource(location);
		//。。。。。。。。。。。。。。。。。
		String name = "applicationConfig: [" + location + "]";
		List<Document> documents = loadDocuments(loader, name, resource); //這里是yml文件的加載解析過程,具體如下代碼
		//。。。。。。。。。。。。。。。。
		List<Document> loaded = new ArrayList<>();
		for (Document document : documents) {
			if (filter.match(document)) {
				addActiveProfiles(document.getActiveProfiles());//設置激活yml配置文件
				addIncludedProfiles(document.getIncludeProfiles());
				loaded.add(document);
			}
		}
		Collections.reverse(loaded);
		if (!loaded.isEmpty()) {
			loaded.forEach((document) -> consumer.accept(profile, document));
		        //。。。。。。。。。。。。。。。。。    
		}
	}
	catch (Exception ex) {
		throw new IllegalStateException("Failed to load property source from location '" + location + "'", ex);
	}
}
//獲取配置文件解析數據
private List<Document> loadDocuments(PropertySourceLoader loader, String name, Resource resource)
				throws IOException {
	DocumentsCacheKey cacheKey = new DocumentsCacheKey(loader, resource);
	List<Document> documents = this.loadDocumentsCache.get(cacheKey);
	if (documents == null) {
		List<PropertySource<?>> loaded = loader.load(name, resource);//又是load方法,這里是yml的數據解析過程
		documents = asDocuments(loaded);
		this.loadDocumentsCache.put(cacheKey, documents); 
	}
	return documents;
}


YamlPropertySourceLoader 加載yml配置文件

       這個類是YML文件的加載解析類,下面的類是具體的解析操作

@Override
public List<PropertySource<?>> load(String name, Resource resource) throws IOException {
	if (!ClassUtils.isPresent("org.yaml.snakeyaml.Yaml", null)) {
		throw new IllegalStateException(
				"Attempted to load " + name + " but snakeyaml was not found on the classpath");
	}
	List<Map<String, Object>> loaded = new OriginTrackedYamlLoader(resource).load();//解析yml配置數據
	if (loaded.isEmpty()) {
		return Collections.emptyList();
	}
	List<PropertySource<?>> propertySources = new ArrayList<>(loaded.size());
	for (int i = 0; i < loaded.size(); i++) {
		String documentNumber = (loaded.size() != 1) ? " (document #" + i + ")" : "";
		propertySources.add(new OriginTrackedMapPropertySource(name + documentNumber,
				Collections.unmodifiableMap(loaded.get(i)), true));
	}
	return propertySources;
}

OriginTrackedYamlLoader類

      load()方法用於解析數據,將YML配置參數解析成為MAP集合

List<Map<String, Object>> load() {
	final List<Map<String, Object>> result = new ArrayList<>();
	process((properties, map) -> result.add(getFlattenedMap(map)));
	return result;
}

// YamlProcess類的process方法進行yml文件解析

protected void process(MatchCallback callback) {
	Yaml yaml = createYaml();
	for (Resource resource : this.resources) {
		boolean found = process(callback, yaml, resource);
		if (this.resolutionMethod == ResolutionMethod.FIRST_FOUND && found) {
			return;
		}
	}
}

      以上就是springboot啟動時environment的加載過程。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM