springboot配置多个yml文件,springboot读取自定义yml文件
00-1010 1、序列2、加载自定义yml文件2.1、读取带@ propertysource批注的yml配置文件-简单版2.2、读取带@ propertysource批注的yml配置文件-非简单版?2.3.前缀可行版本3,外部部署3.1,外部加载spring boot核心配置文件3.2,在@PropertySource中添加路径3.3,通过YamlPropertiesFactoryBean添加路径3.4,自定义yaml文件资源加载类。
00-1010背景:有一个小项目需要背景。我是以Java Disruption为名拍的,被男票安利春装开机很疯狂,于是(被迫无所事事)开始了边开发边学习的道路.很好吃,信息量很大,而且超级好用!
对于电厂项目,使用公司自己开发的实时数据库。后台涉及的很多测点的信息都需要存储在配置文件中(不要问我为什么不是关系数据库),希望部署时可以方便修改。考虑到内容比较多,放在application-pro.yml里确实不合适,所以我加了一个point.yml并不是因为现场测点信息会发生变化才需要更改。更有甚者,突然一拍脑袋,发现手在抖,写错了?
首先,因为不小心变成了xxx.yml播放器,用的不错,但是回不去xxx.properties,传说官方不支持像xxx一样使用annotation @ property source( class path 3360 XXX . properties )加载yml配置文件。以下是如何加载自定义的yml文件。
看一下官方说明
关于加载自定义xxx.properties文件的方法,请参考本文:
跳靴的性能配置分析
注:我之前在找多数据源配置的数据的时候,因为数据对应的spring boot版本不同,很郁闷。请注意,我使用的版本是:
弹簧靴2.13
目录
春开机资料很多,多到想都不用想就能解决问题,非常容易~项目做完之后冷静下来,我觉得还是要验证一下。毕竟打人家脸是为了以后出人头地。
00-1010根据上面给出的官方公告,这条路是走不通的。因为没有看到文档对应的版本号,所以还是试试吧:
#配置文件point . yml id 3360 2233 name 3360 Ellie(诶,这种信息为什么叫point?
//配置相应的配置类@ data @ configuration @ property source(value={ class path : point . yml })@ configuration properties()public class test point { private int id;私有字符串名称;@ Override public String to String(){ return test point { id= id ,name= name }}}粘贴一个控制器进行测试。
@RestControllerpublic类TestConfigController { @ Resource test point test point;@ApiOperation(测试配置文件)@ request mapping(value=/config )public resultbeanstalling test config(){ return resultbeanutil . makeokersep(test point . tostring());} }邮差,起来
一切都好!
所以如果只是想读取这么简单的信息,可以直接使用annotation @ propertysource。不知道官方不确定的影响是什么。
00-1010添加一个列表基本类型看看。
# point.ymlid: 2233na
me: Elliecards: - XD02101263 - ZY8965 - GX0009 // 配置类 @Data@Configuration@PropertySource(value = {"classpath:point.yml"})@ConfigurationProperties()public class TestPoint { private int id; private String name; private List<String> cards; @Override public String toString() { return "TestPoint{" + "id=" + id + ", name=" + name + + ", cards=" + cards + }; }}postman
装逼失败,不行了哦。使用@Value("id")注解也是不行的呢,因为这个注解是用来匹配变量名称和配置文件不一致的情况。
按照其他博客里讲的(才糊代码一个月根本没有深入看原理的我只好是:大佬说啥就是啥),是因为使用@PropertySource注解只能加载yml配置文件,但不能将其配置信息暴露给spring environment,需要手动暴露。方法就是在让application启动的时候把下面的bean加载。
@Beanpublic static PropertySourcesPlaceholderConfigurer properties() {PropertySourcesPlaceholderConfigurer configurer = new PropertySourcesPlaceholderConfigurer();YamlPropertiesFactoryBean yaml = new YamlPropertiesFactoryBean();yaml.setResources(new ClassPathResource("point.yml"));configurer.setProperties(yaml.getObject());return configurer;}
偷懒的我直接丢到了main函数所在的.java文件。运行:
真的不是我截错图哦。
2.3、加前缀可行版
毕竟我这么机智(无脑分析!),悄咪咪加了个前缀,前缀的名字随意取哈,与配置类中对应即可,我只是偷懒叫做prefix。
# point.ymlprefix: id: 2233 name: Ellie cards: - XD02101263 - ZY8965 - GX0009 // config类 @Data@Configuration@PropertySource(value = {"classpath:point.yml"})@ConfigurationProperties(prefix = "prefix") public class TestPoint { private int id; private String name; private List<String> cards; @Override public String toString() { return "TestPoint{" + "id=" + id + ", name=" + name + + ", cards=" + cards + }; }}
都挺好大结局?
求助:
这样为什么可行,俺是一点都不晓得的,如果有大佬路过,请帮忙解答!!!跪谢orz
顺便说一句,出于好奇,试了下某些博文里说的前缀加yml分隔符---配合的方式,感觉上是一本正经胡说八道,实际上也没读出来。读取List<类>也是同样可行的。
# point.ymlprefix: id: 2233 name: Ellie cards: - name: XD code: XD02101263 - name: ZY code: ZY8965 - name: GX code: GX0009 // config 类@Data@Configuration@PropertySource(value = {"classpath:point.yml"})@ConfigurationProperties(prefix = "prefix")public class TestPoint { private int id; private String name; private List<Card> cards; @Override public String toString() { return "TestPoint{" + "id=" + id + ", name=" + name + + ", cards=" + cards + }; }}// 并不需要有什么与众不同的card类@Datapublic class Card { private String name; private String code; @Override public String toString() { return "Card{" + "name=" + name + + ", code=" + code + + }; }}
请求
查找资料的过程中还看到了一种别致的写法,是为了解决多层嵌套的yml的读写,未验证,因为有选择的话,我不愿意这样写,不过写法确实很别致,哈哈哈!https:///article/242026.htm
3、外部部署
其实就是把配置文件部署在jar包外部,方便修改而不必重新打包。
3.1、spring boot核心配置文件外部加载
希望外部加载自定义配置文件,需要先了解spring默认的文件加载方式。
spring程序会按优先级从下面这些路径来加载application.properties配置文件:
当前目录下的/config目录当前目录classpath里的/config目录classpath 根目录idea中,在源码下的classpath对应src/main/resources很明确,打包后的classpath在哪里俺是不知道的,然后就把打包后的jar包解压看了下,在BOOT-INFclasses下看到了application.yml和point.yml。所以要想覆盖配置文件,我再jar包同级目录下建了config文件夹,修改配置文件内容看覆盖是否生效。
具体操作:
打包的时候默认将application.yml和point.yml打包到jar中(classpath)部署时,jar包同级目录下建立config文件夹,修改application.yml中端口号和point.yml内容,看修改是否生效。修改后的point.yml文件如下:
prefix: id: 2233 name: FakeEllie cards: - name: NONE code: 00000001
测试结果:端口号修改生效(application.yml修改生效),修改后的point.yml并未生效。
毕竟自定义配置文件,一厢情愿希望spring boot按照核心文件加载方式加载point.yml,没有生效也在意料之中,不过路并没有堵死。
3.2、在@PropertySource中添加路径
查资料的时候注意到还有这种写法:
@Data@Configuration@PropertySource(value = {"file:config/point.yml"})@ConfigurationProperties(prefix = "prefix")public class TestPoint { private int id; private String name; private List<Card> cards; @Override public String toString() { return "TestPoint{" + "id=" + id + ", name=" + name + + ", cards=" + cards + }; }}
就是通过file来指定文件路径,之前是classpath来指定资源相对路径,说来神奇,这种方式没有报错,但读取的内容却是classpath下的point.yml,而不是config下的point.yml。
想来是通过@ConfigurationProperties(prefix = "prefix")指定的前缀去classpath下匹配到的。跟@PropertySource(value = {"file:config/point.yml"})大概是没有关系了,忘崽牛奶真好喝。
3.3、通过YamlPropertiesFactoryBean添加路径
回想上面的描述,YamlPropertiesFactoryBean是将配置文件暴露给spring环境的,可以考虑使用它来指定文件路径。
修改bean,添加new FileSystemResource("config/point.yml")来指定config文件夹下的配置。
@Beanpublic static PropertySourcesPlaceholderConfigurer properties() {PropertySourcesPlaceholderConfigurer configurer = new PropertySourcesPlaceholderConfigurer();YamlPropertiesFactoryBean yaml = new YamlPropertiesFactoryBean();yaml.setResources(new ClassPathResource("point.yml"), new FileSystemResource("config/point.yml"));configurer.setProperties(yaml.getObject());return configurer;}
此时配置类上使用@PropertySource(value = {"file:config/point.yml"})这种写法,返回的是
成功了?但是好像搞笑了。不过也说明了配置文件读取的顺序。config文件夹下的有最终决定权。
为了直观些,俺顺手修改jar包同级目录下config文件夹中point.yml配置文件,保证list元素个数相同:
prefix: id: 2233 name: FakeEllie cards: - name: NONE code: 00000001 - name: NONE code: 00000002 - name: NONE code: 00000003
不搞笑了。
但是,改成此时配置类上使用@PropertySource(value = {"classpath:point.yml"})后,返回并没有变化。所以YamlPropertiesFactoryBean将配置文件暴露给spring环境,说的应该就是将文件添加到spring的classpath下了,先读默认的,再读新添加这样子的。
然鹅这样就没有办法在不进行外部配置的时候使用默认的classpath下的配置文件了。
此外,通过YamlPropertiesFactoryBean添加配置文件的方式,就需要保证config/point.yml一定要存在,要想达到不进行外部配置的时候读取默认classpath下point.yml,在进行外部配置的时候读取config/point.yml。那就只好耍流氓了。
@Data@Configuration@PropertySource(value = {"file:config/point.yml", "classpath:point.yml"}, ignoreResourceNotFound = true)@ConfigurationProperties(prefix = "prefix")public class TestPoint { private int id; private String name; private List<Card> cards; @Override public String toString() { return "TestPoint{" + "id=" + id + ", name=" + name + + ", cards=" + cards + }; }}
重点:然后!在不进行外部配置的时候,config/point.yml内容为空,或者干脆跟classpath下的point.yml内容保持一致。
小孩子才做选择题,我全都想要
虽然看上去像个意外,但是好在意啊啊啊啊,遏制不住的好奇心啊!就是刚刚那个拼起来的返回值。
想看看是不是application.yml覆盖list也会这样,俺把配置类对应的内容举家搬迁到了application.yml中。如下:
// 配置类@Data@Configuration@ConfigurationProperties(prefix = "prefix")public class TestPoint { private int id; private String name; private List<Card> cards; @Override public String toString() { return "TestPoint{" + "id=" + id + ", name=" + name + + ", cards=" + cards + }; }}
配置类默认读取application.yml。
# classpath:application.ymlprefix: id: 2233 name: Ellie cards: - name: XD code: XD02101263 - name: ZY code: ZY8965 - name: GX code: GX0009#config/application.ymlprefix: id: 2233 name: FakeEllie cards: - name: NONE code: 00000001
测试结果:
并没有进行拼接啊喂!!!
在各种调换顺序看影响的时候,修改了YamlPropertiesFactoryBean添加source的顺序,返回结果发生了变化。
@Beanpublic static PropertySourcesPlaceholderConfigurer properties() {PropertySourcesPlaceholderConfigurer configurer = new PropertySourcesPlaceholderConfigurer();YamlPropertiesFactoryBean yaml = new YamlPropertiesFactoryBean();yaml.setResources(new FileSystemResource("config/point.yml"), new ClassPathResource("point.yml"));configurer.setProperties(yaml.getObject()); configurer.setIgnoreResourceNotFound(true);return configurer;}
返回结果
有一种简单的在运行时通过命令参数指定配置文件的方式效果与此类似。
java -jar demo.jar --Dspring.config.location=point.yml
俺的原则时,代码能解决的,就不要交给人来解决。
虽然没有解决任何问题,但是顺便知道了读取的先后顺序就是setResources的先后顺序。卒
所以目前的结论是,对于有list的配置,并且个数发生变化的时候,这种方式并不适用。
3.4、自定义yaml文件资源加载类
在注解@PropertySource中,有个属性factory主要用来声明解析配置文件的类,这个类必须是PropertySourceFactory接口的实现。从这里入手。
参考资料:
Spring Boot自定义加载yml实现,附源码解读
默认调用的是PropertySourceFactory的实现DefaultPropertySourceFactory,因此可以自定义factory实现PropertySourceFactory接口,也可以扩展DefaultPropertySourceFactory类。两种写法的效果是一样的,列出来。
直接实现PropertySourceFactory接口
public class YamlPropertyLoaderFactory implements PropertySourceFactory { @Override public PropertySource<?> createPropertySource(String name, EncodedResource encodedResource) throws IOException { List<PropertySource<?>> sources = name != null ? new YamlPropertySourceLoader().load(name, encodedResource.getResource()) : new YamlPropertySourceLoader().load( getNameForResource(encodedResource.getResource()), encodedResource.getResource()); if (sources.size() == 0) { return null; } return sources.get(0); } private static String getNameForResource(Resource resource) { String name = resource.getDescription(); if (!StringUtils.hasText(name)) { name = resource.getClass().getSimpleName() + "@" + System.identityHashCode(resource); } return name; }}
扩展DefaultPropertySourceFactory
public class YamlPropertyLoaderFactory extends DefaultPropertySourceFactory { @Override public PropertySource<?> createPropertySource(String name, EncodedResource resource) throws IOException { if (resource == null) { return super.createPropertySource(name, resource); } List<PropertySource<?>> sources = new YamlPropertySourceLoader().load(resource.getResource().getFilename(), resource.getResource()); if (sources.size() == 0) { return super.createPropertySource(name, resource); } return sources.get(0); }}
建议用第二种方式。
用factory的方式来实现的话,前面莫名其妙加个prefix就可以正常读取的诡异操作也不需要了哦。
使用方式如下:
@Data@Configuration@PropertySource(value = {"classpath:point.yml", "file:config/point.yml"}, factory = YamlPropertyLoaderFactory.class, ignoreResourceNotFound = true)@ConfigurationPropertiespublic class TestPoint{ private int id; private String name; private List<Card> cards; @Override public String toString() { return "TestPoint{" + "id=" + id + ", name=" + name + + ", cards=" + cards + }; }}# config/point.ymlid: 2233name: FakeElliecards: - name: NONE code: 00000001
测试结果:
自定义factory的方式,读取多种路径的配置文件时,也是有先后顺序的,就是@PropertySource中value属性指定的顺序,与使用YamlPropertiesFactoryBean将资源暴露给spring环境不同,这个不会有前面出现的拼接效果出现,棒呆~
以解决问题为目标和以写清楚文章为目标去看同样的问题,真的是不一样的探索路径呢,凑字数和为了flag不倒的文写的远远超出自己最初的预期,真好,超喜欢!
以上为个人经验,希望能给大家一个参考,也希望大家多多支持盛行IT。
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。