通过源码了解springboot加载application.properties过程
通过源码了解springboot加载application.properties过程
原创天才小汪汪 发布于2018-09-27 16:52:31 阅读数 2494 收藏
展开
springboot有一个配置文件application.properties,我只知道有这么一个配置文件,但是springboot启动的时候,是在哪里加载该文件的,又如何找到该文件的?从源码去查看
在main方法里执行该方法SpringApplication.run(Test.class, args);查看SpringApplication类的源码,进入run方法
public static ConfigurableApplicationContext run(Object source, String... args) {
return run(new Object[] { source }, args);
}
再进入 run(new Object[] { source }, args);方法
public static ConfigurableApplicationContext run(Object[] sources, String[] args) {
return new SpringApplication(sources).run(args);
}
到这一步,可以看到创建一个新的SpringApplication,new SpringApplication(sources),并执行run()方法,先到构造方法去看一下,这类做了什么初始化的事
public SpringApplication(Object... sources) {
initialize(sources);
}
里面有一个initialize(sources);方法,再进去
@SuppressWarnings({ "unchecked", "rawtypes" })
private void initialize(Object[] sources) {
if (sources != null && sources.length > 0) {
this.sources.addAll(Arrays.asList(sources));
}
this.webEnvironment = deduceWebEnvironment();
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
在上面的代码中, this.webEnvironment = deduceWebEnvironment();该方法主要是筛选sevlet和ConfigurableWebApplicationContext,如何有这两个就返回false,否则返回true,具体有什么作用,我也不知道,但跟这次讨论的问题无关,暂时放一边,setInitalizers()方法,看一下源码
public void setInitializers(
Collection<? extends ApplicationContextInitializer<?>> initializers) {
this.initializers = new ArrayList<ApplicationContextInitializer<?>>();
this.initializers.addAll(initializers);
}
该方法就是将ApplicationContextInitializer的实现类加入 this.initializers集合中,在getSpringFactoriesInstances(
ApplicationContextInitializer.class)方法中,利用反射获取实现类的集合
private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type,
Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
// Use names and ensure unique to protect against duplicates
Set<String> names = new LinkedHashSet<String>(
SpringFactoriesLoader.loadFactoryNames(type, classLoader));
List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
在this.initializers中存放的就springboot所要加载的ApplicationContextInitializer实现类
[org.springframework.boot.context.config.DelegatingApplicationContextInitializer,
org.springframework.boot.context.ContextIdApplicationContextInitializer,
org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,
org.springframework.boot.context.embedded.ServerPortInfoApplicationContextInitializer,
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,
org.springframework.boot.autoconfigure.logging.AutoConfigurationReportLoggingInitializer]
在这些实现类中,也没有涉及到application.properties文件的加载,暂时也不管,来看 setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));方法,和上面加载ApplicationContextInitializer步骤一样,在this.listeners存储的ApplicationListener便有以下这些
[org.springframework.boot.context.config.ConfigFileApplicationListener,
org.springframework.boot.context.config.AnsiOutputApplicationListener,
org.springframework.boot.logging.LoggingApplicationListener,
org.springframework.boot.logging.ClasspathLoggingApplicationListener,
org.springframework.boot.autoconfigure.BackgroundPreinitializer,
org.springframework.boot.context.config.DelegatingApplicationListener,
org.springframework.boot.builder.ParentContextCloserApplicationListener,
org.springframework.boot.ClearCachesApplicationListener
org.springframework.boot.context.FileEncodingApplicationListener,
org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener]
到这里便可以看到一个很重要的监听器ConfigFileApplicationListener
public class ConfigFileApplicationListener implements EnvironmentPostProcessor,
ApplicationListener<ApplicationEvent>, Ordered {
private static final String DEFAULT_PROPERTIES = "defaultProperties";
// Note the order is from least to most specific (last one wins)
private static final String DEFAULT_SEARCH_LOCATIONS = "classpath:/,classpath:/config/,file:./,file:./config/"; //默认 加载的位置
private static final String DEFAULT_NAMES = "application"; //默认的配置文件名
/**
* The "active profiles" property name.
*/
public static final String ACTIVE_PROFILES_PROPERTY = "spring.profiles.active";
/**
* The "includes profiles" property name.
*/
public static final String INCLUDE_PROFILES_PROPERTY = "spring.profiles.include";
/**
* The "config name" property name.
*/
public static final String CONFIG_NAME_PROPERTY = "spring.config.name";
/**
* The "config location" property name.
*/
public static final String CONFIG_LOCATION_PROPERTY = "spring.config.location";
/**
* The default order for the processor.
*/
public static final int DEFAULT_ORDER = Ordered.HIGHEST_PRECEDENCE + 10;
/**
* Name of the application configuration {@link PropertySource}.
*/
public static final String APPLICATION_CONFIGURATION_PROPERTY_SOURCE_NAME = "applicationConfigurationProperties";
private final DeferredLog logger = new DeferredLog();
private String searchLocations;
private String names;
private int order = DEFAULT_ORDER;
private final ConversionService conversionService = new DefaultConversionService();
@Override
public void onApplicationEvent(ApplicationEvent event) {
.............................
}
................
}
到这里终于找到了加载application.properties的类了,该类便是解析application.properties里配置的各个属性值,在prependProfile()方法解析.
以上,SpringApplication只是将该类存在一个集合中,那么它又是在哪里开启这些监听呢
到这里,进入run()方法去看一下
public ConfigurableApplicationContext run(String... args) {
//...........
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
//...................
}
在这里,得到的是一个SpringApplicationRunListeners的实现类EventPublishingRunListener,并将其开启监听,EventPublishingRunListener里面如下做了如下处理
public EventPublishingRunListener(SpringApplication application, String[] args) {
this.application = application;
this.args = args;
this.initialMulticaster = new SimpleApplicationEventMulticaster();
for (ApplicationListener<?> listener : application.getListeners()) {
this.initialMulticaster.addApplicationListener(listener);
}
}
在EventPublishingRunListener的构造函数里,application.getListeners()获取的就是SpringApplication中的this.listeners集合里存放的Listener.再来看listeners.starting();方法做了什么
public void starting() {
for (SpringApplicationRunListener listener : this.listeners) {
listener.starting();
}
}
它把集合里的所有listener都开启了监听.到此加载application.properties结束.
总结:
springboot通过SpringApplication类的构造函数,加载所需要的listener,在run()方法执行里,由EventPublishingRunListener开启所有的listener的监听.
————————————————
版权声明:本文为CSDN博主「天才小汪汪」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_36009027/article/details/82868431