spring boot application

spring boot默认已经配置了很多环境变量,例如,tomcat的默认端口是8080,项目的contextpath是“/”等等,spring boot允许你自定义一个application.properties文件,然后放在以下的地方,来重写spring boot的环境变量

spring对配置application.properties的加载过程:

  1. 服务启动调用:SpringApplication.run
  2. 创建默认的环境参数:ConfigurableEnvironment
  3. 触发事件:ApplicationEnvironmentPreparedEvent
  4. 完成加载

整个过程主要使用spring boot 内置的ConfigFileApplicationListener监听器监听ApplicationEnvironmentPreparedEvent事件完成对application.properties加载以及设置。


下面我们来跟踪源码,看下spring boot是怎样完成对application.properties文件的加载

  • SpringApplication 入口 run:
public ConfigurableApplicationContext run(String... args) {//无关的代码暂略.......ConfigurableApplicationContext context = null;FailureAnalyzers analyzers = null;configureHeadlessProperty();//获取执行监听器实例SpringApplicationRunListeners listeners = getRunListeners(args);........//创建全局系统参数实例ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);//创建    ConfigurableEnvironment 并触发ApplicationEnvironmentPreparedEvent事件    //加载配置的核心地方,spring启动首要做的事情ConfigurableEnvironment environment = prepareEnvironment(listeners,applicationArguments);.........}

prepareEnvironment方法

private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,ApplicationArguments applicationArguments) {// Create and configure the environment//创建一个配置环境信息,当是web环境时创建StandardServletEnvironment实例,非web环境时创建StandardEnvironment实例ConfigurableEnvironment environment = getOrCreateEnvironment();configureEnvironment(environment, applicationArguments.getSourceArgs());//核心事件触发方法,此方法执行后会执行所有监听ApplicationEnvironmentPreparedEvent事件的监听器,这里我们是跟踪application.properties文件的加载,就查看ConfigFileApplicationListener监听器都做了什么工作listeners.environmentPrepared(environment);if (!this.webEnvironment) {environment = new EnvironmentConverter(getClassLoader()).convertToStandardEnvironmentIfNecessary(environment);}return environment;}
  • ConfigFileApplicationListener:
public void onApplicationEvent(ApplicationEvent event) {//从此处可以看到当事件为ApplicationEnvironmentPreparedEvent时,执行onApplicationEnvironmentPreparedEvent方法if (event instanceof ApplicationEnvironmentPreparedEvent) {onApplicationEnvironmentPreparedEvent((ApplicationEnvironmentPreparedEvent) event);}if (event instanceof ApplicationPreparedEvent) {onApplicationPreparedEvent(event);}}

onApplicationEnvironmentPreparedEvent

private void onApplicationEnvironmentPreparedEvent(ApplicationEnvironmentPreparedEvent event) {//此处通过SpringFactoriesLoader加载EnvironmentPostProcessor所有扩展   List postProcessors = loadPostProcessors();//因为此监听器同样是EnvironmentPostProcessor的扩展实例,所以在此处将自己加入集合postProcessors.add(this);AnnotationAwareOrderComparator.sort(postProcessors);//遍历所有的EnvironmentPostProcessor扩展调用postProcessEnvironment//当然我们跟踪是application.properties所以主要查看当前实例的postProcessEnvironment方法for (EnvironmentPostProcessor postProcessor : postProcessors) {postProcessor.postProcessEnvironment(event.getEnvironment(),event.getSpringApplication());}}

postProcessEnvironment

@Overridepublic void postProcessEnvironment(ConfigurableEnvironment environment,SpringApplication application) {//此处添加配置信息到environment实例中,此方法完成后就将application.properties加载到环境信息中addPropertySources(environment, application.getResourceLoader());configureIgnoreBeanInfo(environment);bindToSpringApplication(environment, application);}

addPropertySources

protected void addPropertySources(ConfigurableEnvironment environment,ResourceLoader resourceLoader) {//这里先添加一个Random名称的资源到环境信息中  RandomValuePropertySource.addToEnvironment(environment);//通过Loader加载application.properties并将信息存入环境信息中new Loader(environment, resourceLoader).load();}

load

public void load() {
//创建一个资源加载器,spring boot默认支持PropertiesPropertySourceLoader,YamlPropertySourceLoader两种配置文件的加载this.propertiesLoader = new PropertySourcesLoader();this.activatedProfiles = false;//加载配置profile信息,默认为default..........此处省略while (!this.profiles.isEmpty()) {Profile profile = this.profiles.poll();//遍历所有查询路径,默认路径有:classpath:/,classpath:/config/,file:./,file:./config/for (String location : getSearchLocations()) {//这里不仅仅是加载application.properties,当搜索路径不是以/结束,默认认为是文件名已存在的路径if (!location.endsWith("/")) {// location is a filename already, so don't search for more// filenamesload(location, null, profile);}else {//遍历要加载的文件名集合,默认为applicationfor (String name : getSearchNames()) {load(location, name, profile);}}}this.processedProfiles.add(profile);}//将加载完成的配置信息全部保存到环境信息中共享addConfigurationProperties(this.propertiesLoader.getPropertySources());}

load

private void load(String location, String name, Profile profile) {//此处根据profile组装加载的文件名称以及资源所放置的组信息String group = "profile=" + (profile == null ? "" : profile);if (!StringUtils.hasText(name)) {// Try to load directly from the locationloadIntoGroup(group, location, profile);}else {// Also try the profile-specific section (if any) of the normal fileloadIntoGroup(group, location + name + "." + ext, profile);}}}

loadIntoGroup

private PropertySource doLoadIntoGroup(String identifier, String location,Profile profile) throws IOException {Resource resource = this.resourceLoader.getResource(location);PropertySource propertySource = null;if (resource != null && resource.exists()) {String name = "applicationConfig: [" + location + "]";String group = "applicationConfig: [" + identifier + "]";//资源加载核心方法,此处有两个实现,当后缀为,xml或者properties调用PropertiesPropertySourceLoader//当后缀为yml或者yaml时,调用YamlPropertySourceLoaderpropertySource = this.propertiesLoader.load(resource, }return propertySource;}
  • PropertiesPropertySourceLoader:
@Overridepublic PropertySource load(String name, Resource resource, String profile)throws IOException {if (profile == null) {//此处调用PropertiesLoaderUtils工具类加载本地文件Properties properties = PropertiesLoaderUtils.loadProperties(resource);if (!properties.isEmpty()) {return new PropertiesPropertySource(name, properties);}}return null;}

到此application.properties就真正的加载并共享到环境信息中,供系统其它地方调用



 


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部