SpringApplication.run()
方法底层调用过程
1、在 Spring Boot 的应用程序类的main
方法中,调用了SpringApplication
类中的run()
方法。
package fun.hara.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class BootApplication {
public static void main(String [] args){
SpringApplication.run(BootApplication.class, args);
System.out.println("项目已启动...");
}
}
2、SpringApplication
中的run()
方法会调用同类中的getSpringFactoriesInstances()
方法。
在该方法中调用了SpringFactoriesLoader
类中的loadFactoryNames
获取工厂名,并完成实例化相关操作。
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = this.getClassLoader();
// 加载工厂名字
Set<String> names = new LinkedHashSet
(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
// 实例化相关操作
List<T> instances = this.createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
3、 SpringFactoriesLoadaer
类中的loadSpringFactories()
方法会去读取spring.properties
配置文件。
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
MultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader);
if (result != null) {
return result;
} else {
try {
// 工厂类配置文件
Enumeration<URL> urls = classLoader != null ?
classLoader.getResources("META-INF/spring.factories") :
ClassLoader.getSystemResources("META-INF/spring.factories");
LinkedMultiValueMap result = new LinkedMultiValueMap();
// 其余代码略 ...
Spring.factories
配置文件
该配置文件在spring-boot-autoconfigure-2.2.0.RELEASE.jar
包的/META-INF/
路径下。
Spring.factories
# Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\
org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener
# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.autoconfigure.BackgroundPreinitializer
# ...
org.springframework.boot.autoconfigure.solr.SolrAutoConfiguration,\
# 其余配置略
可以看到,该配置文件中主要是包含了各种类的全限定名。
以SolrAutoConfiguration
类为例:
package org.springframework.boot.autoconfigure.solr;
// 部分代码略
@Configuration(
proxyBeanMethods = false
)
@ConditionalOnClass({HttpSolrClient.class, CloudSolrClient.class}) // 类加载的条件
@EnableConfigurationProperties({SolrProperties.class}) // 对于的配置文件
public class SolrAutoConfiguration {
public SolrAutoConfiguration() {
}
@Bean
@ConditionalOnMissingBean
public SolrClient solrClient(SolrProperties properties) {
return (SolrClient)(StringUtils.hasText(properties.getZkHost()) ? (new Builder(Arrays.asList(properties.getZkHost()), Optional.empty())).build() : (new org.apache.solr.client.solrj.impl.HttpSolrClient.Builder(properties.getHost())).build());
}
}
SolrProperties
类
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package org.springframework.boot.autoconfigure.solr;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(
prefix = "spring.data.solr"
)
public class SolrProperties {
private String host = "http://127.0.0.1:8983/solr";
private String zkHost;
public SolrProperties() {
}
public String getHost() {
return this.host;
}
public void setHost(String host) {
this.host = host;
}
public String getZkHost() {
return this.zkHost;
}
public void setZkHost(String zkHost) {
this.zkHost = zkHost;
}
}
可以看到,SolrProperties
类包含了Solr
相关的默认配置。我们也可在application.properties
或application.yml
中自定义配置值来覆盖默认的配置。
小结
SpringApplication.run()
方法中调用了SpringFactoriesLoader.loadFactoryNames()
方法,通过读取spring.factories
,得到各种Configuration
类的全限定名,在根据每个类的加载条件觉得是否加载该类完成实例化。
另外每个Configuration
类通过Properties
类中的默认配置完成所支持的技术框架的配置,我们可以通过全局配置文件来修改覆盖默认配置。