ApplicationArguments 提供对用于运行的参数的访问
ConfigurableEnvironment 的propertySources 存放yml的配置参数
getSearchLocations 获取默认文件放置路径 classpath:/,classpath:/config/,file:./,file:./config/
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);
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
configureIgnoreBeanInfo(environment);
*********其它跟本业务无关的先注掉***********************
}
*********其它跟本业务无关的先注掉***********************
return context;
}
getOrCreateEnvironment 返回一个标准的servlet环境类
private ConfigurableEnvironment prepareEnvironment(
SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments) {
// Create and configure the environment
ConfigurableEnvironment environment = getOrCreateEnvironment();
configureEnvironment(environment, applicationArguments.getSourceArgs());
listeners.environmentPrepared(environment);
bindToSpringApplication(environment);
if (this.webApplicationType == WebApplicationType.NONE) {
environment = new EnvironmentConverter(getClassLoader())
.convertToStandardEnvironmentIfNecessary(environment);
}
ConfigurationPropertySources.attach(environment);
return environment;
}
EventPublishingRunListener实现了SpringApplicationRunListener接口
environmentPrepared配置environment
public void environmentPrepared(ConfigurableEnvironment environment) {
this.initialMulticaster.multicastEvent(new ApplicationEnvironmentPreparedEvent(
this.application, this.args, environment));
}
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
Executor executor = getTaskExecutor();
if (executor != null) {
executor.execute(() -> invokeListener(listener, event));
}
else {
//执行这一行
invokeListener(listener, event);
}
}
}
************************一直往下跟
loadPostProcessors加载4个进程类
1、SystemEnvironmentPropertySourceEnvironmentPostProcessor
2、SpringApplicationJsonEnvironmentPostProcessor
3、CloudFoundryVcapEnvironmentPostProcessor
4、ConfigFileApplicationListener 加载配置文件
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());
}
}
进入ConfigFileApplicationListener 的addPropertySources 方法加载文件,实例化environment
protected void addPropertySources(ConfigurableEnvironment environment,
ResourceLoader resourceLoader) {
RandomValuePropertySource.addToEnvironment(environment);
new Loader(environment, resourceLoader).load();
}
内部类 Loader 和load方法
public void load() {
this.profiles = Collections.asLifoQueue(new LinkedList<Profile>());
this.processedProfiles = new LinkedList<>();
this.activatedProfiles = false;
this.loaded = new LinkedHashMap<>();
initializeProfiles();
while (!this.profiles.isEmpty()) {
Profile profile = this.profiles.poll();
//如果profiles文件不为空,那么加载文件
load(profile, this::getPositiveProfileFilter,
addToLoaded(MutablePropertySources::addLast, false));
this.processedProfiles.add(profile);
}
load(null, this::getNegativeProfileFilter,
addToLoaded(MutablePropertySources::addFirst, true));
addLoadedPropertySources();
}
getSearchLocations 获取默认文件放置路径 classpath:/,classpath:/config/,file:./,file:./config/
然后遍历加载路径下的文件名 application 后缀为properties,XML,yml,yaml
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存放的目录,然后执行加载
private void load(PropertySourceLoader loader, String location, Profile profile,
DocumentFilter filter, DocumentConsumer consumer) {
try {
Resource resource = this.resourceLoader.getResource(location);
String description = getDescription(location, resource);
if (profile != null) {
description = description + " for profile " + profile;
}
if (resource == null || !resource.exists()) {
this.logger.trace("Skipped missing config " + description);
return;
}
if (!StringUtils.hasText(
StringUtils.getFilenameExtension(resource.getFilename()))) {
this.logger.trace("Skipped empty config extension " + description);
return;
}
String name = "applicationConfig: [" + location + "]";
List<Document> documents = loadDocuments(loader, name, resource);
if (CollectionUtils.isEmpty(documents)) {
this.logger.trace("Skipped unloaded config " + description);
return;
}
List<Document> loaded = new ArrayList<>();
for (Document document : documents) {
if (filter.match(document)) {
maybeActivateProfiles(document.getActiveProfiles());
addProfiles(document.getIncludeProfiles());
loaded.add(document);
}
}
Collections.reverse(loaded);
if (!loaded.isEmpty()) {
loaded.forEach((document) -> consumer.accept(profile, document));
this.logger.debug("Loaded config file " + description);
}
}
catch (Exception ex) {
throw new IllegalStateException("Failed to load property "
+ "source from location '" + location + "'", ex);
}
}
loadDocuments(loader, name, resource)
private List<Document> loadDocuments(PropertySourceLoader loader, String name,
Resource resource) throws IOException {
//获取resource 对应的缓存key
DocumentsCacheKey cacheKey = new DocumentsCacheKey(loader, resource);
List<Document> documents = this.loadDocumentsCache.get(cacheKey);
if (documents == null) {
//缓存中没有才执行load 方法加载
List<PropertySource<?>> loaded = loader.load(name, resource);
documents = asDocuments(loaded);
this.loadDocumentsCache.put(cacheKey, documents);
}
return documents;
}
OriginTrackedYamlLoader yaml文件加载器
public List<Map<String, Object>> load() {
final List<Map<String, Object>> result = new ArrayList<>();
//回调函数 result.add(getFlattenedMap(map)
process((properties, map) -> result.add(getFlattenedMap(map)));
//返回最后加载的数据
return result;
}
protected void process(MatchCallback callback) {
Yaml yaml = createYaml();
for (Resource resource : this.resources) {
//最后加载文件的方法 process(callback, yaml, resource)
boolean found = process(callback, yaml, resource);
if (this.resolutionMethod == ResolutionMethod.FIRST_FOUND && found) {
return;
}
}
}
这里是引用
private boolean process(MatchCallback callback, Yaml yaml, Resource resource) {
int count = 0;
try {
if (logger.isDebugEnabled()) {
logger.debug("Loading from YAML: " + resource);
}
Reader reader = new UnicodeReader(resource.getInputStream());
try {
for (Object object : yaml.loadAll(reader)) {
//将加载的yml文件内容转换成map,然后执行callback 方法将map里的内容放入result 中
if (object != null && process(asMap(object), callback)) {
count++;
if (this.resolutionMethod == ResolutionMethod.FIRST_FOUND) {
break;
}
}
}
//省略****
}
finally {
reader.close();
}
}
catch (IOException ex) {
handleProcessError(resource, ex);
}
return (count > 0);
}
URLClassLoader以流的形式加载文件返回 BufferedInputStream,然后包装成Reader
public InputStream getResourceAsStream(String name) {
URL url = getResource(name);
try {
if (url == null) {
return null;
}
URLConnection urlc = url.openConnection();
InputStream is = urlc.getInputStream();
if (urlc instanceof JarURLConnection) {
JarURLConnection juc = (JarURLConnection)urlc;
JarFile jar = juc.getJarFile();
synchronized (closeables) {
if (!closeables.containsKey(jar)) {
closeables.put(jar, null);
}
}
} else if (urlc instanceof sun.net.www.protocol.file.FileURLConnection) {
synchronized (closeables) {
closeables.put(is, null);
}
}
return is;
} catch (IOException e) {
return null;
}
}