情景描述

最近新搭建了一个项目,从Spring迁到了Springboot,为了兼容Spring加载配置文件的风格,所以还想把PropertyPlaceholderConfigurer放在.xml文件里面,然后通过@importSource来加载.xml文件将配置加载到spring环境中,通过@value或者PropertyUtil来引入对应配置的值。于是发现了以下问题,并根据这些问题进行了问题拓展。

问题描述

1.在.xml引入PropertyPlaceholderConfigurer时,若项目中存在@PropertySource注解,@ConfigurationProperties可以正常加载PropertySource中的配置(启动时发现Bean正常),但是@Value会在启动时报错解析不了占位符;若@ConfigurationProperties加载的是.xml中配置文件的值,则也为空。

2.在使用PropertyUtil(由.xml加载配置)时发现,在通过.xml加载配置的这个方法上,public static 变量在@Configuration的配置类通过PropertyUtil获取配置值时PropertyUtil还未加载(值为null),在其他@Component(包括@Controller)中是可以正常获取到值(说明已经加载)。

解决方案&原理分析

问题1:

其中@PropertySource注解管理的所有配置文件相当于一个PropertyPlaceholderConfigurer,只不过是Springboot自己管理的,而.xml中的PropertyPlaceholderConfigurer又是一个,这就会出现多个PropertyPlaceholderConfigurer的问题(目测是由于先加载了@ImportSource中.xml的PropertyPlaceholderConfigurer导致该问题),多PropertyPlaceholderConfigurer问题原因如下:

在spring bean装配时,一个PropertyPlaceholderConfigurer就是一个后置处理器BeanFactoryPostProcessor。在装配完PropertyPlaceholderConfigurer之后,就会触发org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(Collection<? extends BeanFactoryPostProcessor>, ConfigurableListableBeanFactory)方法,代码如下:

/**
* Invoke the given BeanFactoryPostProcessor beans.
*/
private void invokeBeanFactoryPostProcessors(
Collection<? extends BeanFactoryPostProcessor> postProcessors, ConfigurableListableBeanFactory beanFactory) { for (BeanFactoryPostProcessor postProcessor : postProcessors) {
postProcessor.postProcessBeanFactory(beanFactory);
}
}

每调用完一个BeanFactoryPostProcessor之后,就会去解析所有的bean中引用properties的占位符,这时就会出现占位符不能解析的问题(不能解析的占位在后面的BeanFactoryPostProcessor中,也就是PropertyPlaceholderConfigurer实例)。

而在使用@Value时,由于使用了占位符,而.xml中的PropertyPlaceholderConfigurer先加载解析占位符但是该配置未存在,所以会报错占位符解析失败。

而使用@ConfigurationProperties时,并没有使用占位符,所以如果是在@PropertySource中的配置可以正常加载

但是我个人理解@ConfigurationProperties加载配置是用的@PropertySource的PropertyPlaceholderConfigurer,所以如果配置不是用@PropertySource加载,则加载结果为null(建议配套使用)

解决方法:

<property name="ignoreUnresolvablePlaceholders" value="true"/>

加上上面的一行,表示可以忽略未解析到的占位符。这样就不会报错。

问题2:

我理解@Confituration标识的配置类是在@ImportSource加载.xml之前文件开始加载的,所以它的static值在从PropertyUtil获取值时,PropertyUtil并没有加载配置,所以都为空,但是@Component也即bean加载是在@ImportSource之后的,所以static变量可以获取到正常值。
经过试验,我发现@Value在@Configuration标识的配置类中是可以正常获取到.xml加载的值的,这样表明@Value应该是在@ImportSource之后注入的了。

附:

@PropertySource API:Resource location wildcards (e.g. **/*.properties) are not permitted; each location must evaluate to exactly one .properties resource.(不允许使用资源位置通配符(例如** / *.属性);每个位置必须只评估一个.properties资源)

如果对我上面的分析存在异议欢迎讨论啊,希望相互提高。

转载请注明:https://www.cnblogs.com/fnlingnzb-learner/p/11067338.html

SpringBoot加载配置文件(@PropertySource@importSource@Value)的更多相关文章

  1. Springboot 加载配置文件源码分析

    Springboot 加载配置文件源码分析 本文的分析是基于springboot 2.2.0.RELEASE. 本篇文章的相关源码位置:https://github.com/wbo112/blogde ...

  2. SpringBoot加载配置文件的几种方式

    首先回忆一下在没有使用SpringBoot之前也就是传统的spring项目中是如何读取配置文件,通过I/O流读取指定路径的配置文件,然后再去获取指定的配置信息. 传统项目读取配置方式 读取xml配置文 ...

  3. SpringBoot 加载配置文件

    1.application.properties或application.yaml是SpringBoot默认的配置文件. 可以通过@Value注解 配合 ${......}来读取配置在属性文件中的内容 ...

  4. SpringBoot是如何加载配置文件的?

    前言 本文针对版本2.2.0.RELEASE来分析SpringBoot的配置处理源码,通过查看SpringBoot的源码来弄清楚一些常见的问题比如: SpringBoot从哪里开始加载配置文件? Sp ...

  5. springboot加载外部配置文件

    网上搜集和整理如下(自己已验证过) 1. war包在tomcat中加载外部配置文件 war包运行在独立tomcat下时,如何加载war包外部配置application.properties,以达到每次 ...

  6. springboot属性类自动加载配置文件中的值

    springboot属性类自动加载配置文件中的值,如Person类加载在yml中配置的name,age等属性值,可以通过如下步骤获取: 类上添加@ConfigurationProperties注解,p ...

  7. SpringBoot加载子模块配置文件的方法

    这两天开始学习SpringBoot框架,按照官方的文档,很轻易地就把单模块的项目启动了,但在使用maven搭建多模块的时候遇到了子模块配置文件没有加载的问题 项目架构是这样的 zero |-ws |- ...

  8. 微服务架构 | *2.3 Spring Cloud 启动及加载配置文件源码分析(以 Nacos 为例)

    目录 前言 1. Spring Cloud 什么时候加载配置文件 2. 准备 Environment 配置环境 2.1 配置 Environment 环境 SpringApplication.prep ...

  9. Spring详解(十)加载配置文件

    在项目中有些参数经常需要修改,或者后期可能会有改动时,那我们最好把这些参数放到properties文件中,在源代码中读取properties里面的配置,这样后期只需要改动properties文件即可, ...

随机推荐

  1. lastlogon

    function Get-ADUserLastLogon($userName) { $dcs = Get-ADDomainController -Filter {Name -like "*& ...

  2. 我的node-webkit笔记

    话不多说,直接上码: index.html <!DOCTYPE html> <html> <head> <meta charset="utf-8&q ...

  3. Sql中substr的使用

    pandas和SQL数据分析实战 https://study.163.com/course/courseMain.htm?courseId=1006383008&share=2&sha ...

  4. Xamarin.FormsShell基础教程(7)Shell项目关于页面的介绍

    Xamarin.FormsShell基础教程(7)Shell项目关于页面的介绍 轻拍标签栏中的About标签,进入关于页面,如图1.8和图1.9所示.它是对应用程序介绍的页面. 该页面源自Views文 ...

  5. winform调用webservice假死怎么解决

    主线程调用外部web service,没有返回时,主线程阻塞了,界面肯定假死耗时操作都是要在工作线程里面执行的.一般情况下winform调用webservice时步骤1添加服务引用---高级----添 ...

  6. Flask自动刷新前端页面(方便调试)livereload

    是不是每次调整模板文件,就要停止flask服务器,重启flask服务器,再去浏览器刷新页面? 有没有办法自动完成这3步呢? 安装livereload即可, 仅仅把app.run() 改为下面的例子就可 ...

  7. [Linux] cronjob指定用户运行脚本,并按日期区分输出日志

    废话不多说,直接上代码,在root的cronjob,指定nginx用户跑cronjob */1 * * * * su nginx -c "/usr/local/scripts/goods.s ...

  8. 工具分享:excel2json,将Excel表格转换为JSON

    此次分享的是github上的一个开源小工具:excel2json,用于把Excel表转换成json对象,并保存到一个文本文件. 项目地址:https://github.com/neil3d/excel ...

  9. JS增删改查localStorage实现搜索历史功能

    <script type="text/javascript"> var referrerPath = "@ViewBag.ReferrerPath" ...

  10. linux install jsoncpp0.5.0

    要安装jsoncpp,首先要下载好scons,再去安装jsoncpp scons下载地址:wget http://prdownloads.sourceforge.NET/scons/scons-2.2 ...