# 分析源码
咱们继续一步一步深入源码
# 从main#run()方法开始
从SpringApplication中的静态run()方法开始,经过多次跳转后将构造一个SpringApplication类(通过跟踪SpringBoot的启动代码),相关代码如下:
//1.spring boot常见应用启动代码
SpringApplication.run(ClientApplication.class, args);
//2.跟踪SpringApplication中的静态方法run(),其随后构造了SpringApplication类,并调用了其实例的私有run()
//构造SpringApplication类,并执行run()
return new SpringApplication(primarySources).run(args);
//3.跟踪SpringApplication构造方法
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
//默认为null
this.resourceLoader = resourceLoader;
//the primary bean sources
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
//推断WebApplicationType类型
this.webApplicationType = WebApplicationType.deduceFromClasspath();
//初始化ApplicationContextInitializer
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
//初始化ApplicationListener
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
//推断main方法类的class
this.mainApplicationClass = deduceMainApplicationClass();
}
# 构造ApplicationContextInitializer
构造SpringApplication类时初始化了ApplicationContextInitializer,接下来深入看下其具体是如何实现的:
//获取META-INF/spring.factories中的对应配置
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type,
Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = getClassLoader();
// Use names and ensure unique to protect against duplicates
//loadFactoryNames()获取指定的配置值
Set<String> names = new LinkedHashSet<>(
SpringFactoriesLoader.loadFactoryNames(type, classLoader));
//根据这些类地址,构造出对应的类来
List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
classLoader, args, names);
//根据@Order对构造出来的类集合进行排序
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
loadFactoryNames中实现了从spring.factories加载出对应的配置值
//获取spring.factories中的配置信息
//FACTORIES_RESOURCE_LOCATION="META-INF/spring.factories"
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
MultiValueMap<String, String> result = cache.get(classLoader);
if (result != null) {
return result;
}
try {
Enumeration<URL> urls = (classLoader != null ?
classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
result = new LinkedMultiValueMap<>();
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
UrlResource resource = new UrlResource(url);
//load资源构造成Properties类
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
for (Map.Entry<?, ?> entry : properties.entrySet()) {
String factoryClassName = ((String) entry.getKey()).trim();
for (String factoryName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
result.add(factoryClassName, factoryName.trim());
}
}
}
cache.put(classLoader, result);
return result;
}
catch (IOException ex) {
throw new IllegalArgumentException("Unable to load factories from location [" +
FACTORIES_RESOURCE_LOCATION + "]", ex);
}
}
# 调用SpringApplication构造实例的run()
关键的来了,这里是整个springboot启动的核心。
public ConfigurableApplicationContext run(String... args) {
//构造一个计时器,并开始计时
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
//配置HeadlessProperty,默认为true
configureHeadlessProperty();
//获取运行的Listeners,并开启监听
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
//准备环境配置,本文关键点。
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);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
try {
listeners.running(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}
深入getRunListeners(args)继续跟踪
//
private SpringApplicationRunListeners getRunListeners(String[] args) {
Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
//同样通过getSpringFactoriesInstances获取spring.factories中的配置
//并构造对应的listener
return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(
SpringApplicationRunListener.class, types, this, args));
}
构造listener时,由于spring.factories中配置了org.springframework.boot.context.event.EventPublishingRunListener,因此会将其构造,且因为EventPublishingRunListener为Spring提供了事件的能力,后续代码中将会多处用到。
prepareEnvironment()方法用于准备环境配置,代码如下:
private ConfigurableEnvironment prepareEnvironment(
SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments) {
// Create and configure the environment
ConfigurableEnvironment environment = getOrCreateEnvironment();
configureEnvironment(environment, applicationArguments.getSourceArgs());
//执行environmentPrepared(),并广播ApplicationEnvironmentPreparedEvent事件
listeners.environmentPrepared(environment);
bindToSpringApplication(environment);
if (!this.isCustomEnvironment) {
environment = new EnvironmentConverter(getClassLoader())
.convertEnvironmentIfNecessary(environment, deduceEnvironmentClass());
}
ConfigurationPropertySources.attach(environment);
return environment;
}
由于environmentPrepared()方法广播了ApplicationEnvironmentPreparedEvent,查找多个相关的监听事件,此处我们只看与加载配置相关的配置,即org.springframework.boot.context.config.ConfigFileApplicationListener#onApplicationEvent()的方法,具体代码如下:
@Override
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof ApplicationEnvironmentPreparedEvent) {
//事件类型为ApplicationEnvironmentPreparedEvent时,执行对应逻辑
onApplicationEnvironmentPreparedEvent(
(ApplicationEnvironmentPreparedEvent) event);
}
if (event instanceof ApplicationPreparedEvent) {
onApplicationPreparedEvent(event);
}
}
private void onApplicationEnvironmentPreparedEvent(
ApplicationEnvironmentPreparedEvent event) {
//load processor
List<EnvironmentPostProcessor> postProcessors = loadPostProcessors();
postProcessors.add(this);
AnnotationAwareOrderComparator.sort(postProcessors);
for (EnvironmentPostProcessor postProcessor : postProcessors) {
//
postProcessor.postProcessEnvironment(event.getEnvironment(),
event.getSpringApplication());
}
}
@Override
public void postProcessEnvironment(ConfigurableEnvironment environment,
SpringApplication application) {
addPropertySources(environment, application.getResourceLoader());
}
protected void addPropertySources(ConfigurableEnvironment environment,
ResourceLoader resourceLoader) {
RandomValuePropertySource.addToEnvironment(environment);
new Loader(environment, resourceLoader).load();
}
//Loader类的构造方法
public 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());
}
//
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) {
//foreach所有配置文件的目录地址
getSearchLocations().forEach((location) -> {
boolean isFolder = location.endsWith("/");
//获取所有配置文件
Set<String> names = isFolder ? getSearchNames() : NO_SEARCH_NAMES;
//forEach加载所有配置文件
names.forEach(
(name) -> load(location, name, profile, filterFactory, consumer));
});
}
//CONFIG_LOCATION_PROPERTY = "spring.config.location";
//CONFIG_ADDITIONAL_LOCATION_PROPERTY = "spring.config.additional-location";
private Set<String> getSearchLocations() {
//如果配置了spring.config.location参数,则获取其参数配置。
if (this.environment.containsProperty(CONFIG_LOCATION_PROPERTY)) {
return getSearchLocations(CONFIG_LOCATION_PROPERTY);
}
//获取配置的spring.config.additional-location参数。
Set<String> locations = getSearchLocations(
CONFIG_ADDITIONAL_LOCATION_PROPERTY);
//添加默认的配置文件读取地址:classpath:/,classpath:/config/,file:./,file:./config/
locations.addAll(
asResolvedSet(ConfigFileApplicationListener.this.searchLocations,
DEFAULT_SEARCH_LOCATIONS));
return locations;
}
//根据propertyName入参来获取已加载在环境变量中的配置
private Set<String> getSearchLocations(String propertyName) {
Set<String> locations = new LinkedHashSet<>();
if (this.environment.containsProperty(propertyName)) {
for (String path : asResolvedSet(
this.environment.getProperty(propertyName), null)) {
if (!path.contains("$")) {
path = StringUtils.cleanPath(path);
if (!ResourceUtils.isUrl(path)) {
path = ResourceUtils.FILE_URL_PREFIX + path;
}
}
locations.add(path);
}
}
return locations;
}
//CONFIG_NAME_PROPERTY = "spring.config.name";
//DEFAULT_NAMES = "application";
private Set<String> getSearchNames() {
//设置spring.config.name
if (this.environment.containsProperty(CONFIG_NAME_PROPERTY)) {
String property = this.environment.getProperty(CONFIG_NAME_PROPERTY);
return asResolvedSet(property, null);
}
//默认按照“application”加载
return asResolvedSet(ConfigFileApplicationListener.this.names, DEFAULT_NAMES);
}
以上代码是Spring如何加载对应的配置文件的流程,但没有具体加载配置文件的细节,接下来我们继续跟踪加载配置文件的细节,从org.springframework.boot.context.config.ConfigFileApplicationListener.Loader#load(org.springframework.boot.context.config.ConfigFileApplicationListener.Profile, org.springframework.boot.context.config.ConfigFileApplicationListener.DocumentFilterFactory, org.springframework.boot.context.config.ConfigFileApplicationListener.DocumentConsumer)
开始
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));
});
}
//为上方的load()
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<>();
for (PropertySourceLoader loader : this.propertySourceLoaders) {
for (String fileExtension : loader.getFileExtensions()) {
if (processed.add(fileExtension)) {
loadForFileExtension(loader, location + name, "." + fileExtension,
profile, filterFactory, consumer);
}
}
}
}
关于源代码的跟踪就到这里了,其实整个流程跟踪下来,对于"spring.config.location"等配置,以及加载配置文件的流程,基本都清晰了。
从最开始run方法跟踪进来,还是挺难读,里面涉及了比较杂的内容,容易让人卡壳,所以,我建议你带着一个目的来读源码,中途遇到其他不太理解的地方,试着了解和猜测其作用,但不要去深究,继续向你的目的前进,直到攻克它。