当前位置: 首页 > 科技观察

你知道读取yml文件的五种高大上的方法吗?

时间:2023-03-16 22:44:59 科技观察

上篇文章我们从源码的角度分析了SpringBoot解析yml配置文件的全过程,所以今天来实战一下,总结一下除了@Value和@ConfigurationProperties还能传什么糟糕的街道。读取yml配置文件内容的方法。1、Environment在Spring中有一个类Environment,可以认为是当前应用运行的环境。它继承了PropertyResolver接口,因此可以用作属性解析器。首先创建一个yml文件,属性如下:person:name:hydra性别:maleage:18使用起来也很简单,直接使用@Autowired注入到要使用的类中,然后调用它的getProperty()方法根据属性名,取出对应的值。@RestControllerpublicclassEnvironmentController{@Autowired私有环境环境;@GetMapping("envTest")privatevoidgetEnv(){System.out.println(environment.getProperty("person.name"));System.out.println(environment.getProperty("person.gender"));IntegerautoClose=environment.getProperty("person.age",Integer.class);System.out.println(自动关闭);StringdefaultValue=environment.getProperty("person.other",String.class,"defaultValue");System.out.println(默认值);}}在上面的例子中,我们可以看到除了简单的获取,Environment提供的方法还可以对获取到的属性值进行类型转换,以及默认值的设置,调用上面的接口,打印结果如下:hydramale18defaultValue除了获取属性外,还可以用来判断激活的配置文件。我们先激活application.yml中的pro文件:spring:profiles:active:pro可以使用acceptProfiles方法检测某个配置文件是否被激活加载,也可以使用getActiveProfiles方法获取所有激活的配置文件。测试接口:@GetMapping("getActiveEnv")privatevoidgetActiveEnv(){System.out.println(environment.acceptsProfiles("pro"));System.out.println(environment.acceptsProfiles("dev"));String[]activeProfiles=environment.getActiveProfiles();for(StringactiveProfile:activeProfiles){System.out.println(activeProfile);}}打印结果:truefalsepro2,YamlPropertiesFactoryBean在Spring中,你也可以使用YamlPropertiesFactoryBean来读取自定义的配置yml文件,而不是局限于application.yml等它激活的配置文件。在使用过程中,只需要通过setResources()方法设置自定义yml配置文件的存放路径,然后通过getObject()方法获取Properties对象,即可使用获取具体属性.这是一个例子:@GetMapping("fcTest")publicvoidymlProFctest(){YamlPropertiesFactoryBeanyamlProFb=newYamlPropertiesFactoryBean();yamlProFb.setResources(newClassPathResource("application2.yml"));属性properties=yamlProFb.getObject();System.out.println(properties.get("person2.name"));System.out.println(properties.get("person2.gender"));System.out.println(properties.toString());}查看运行结果,可以读取到指定application2.yml的内容:susanfemale{person2.age=18,person2.gender=female,person2.name=susan但是这个使用有个问题,就是这个属性只能在这个接口值的请求中获取,如果你写另外一个接口,不使用YamlPropertiesFactoryBean去读取配置文件,即使之前的方法已经读取yml文件一次,第二个接口仍然得到一个空值。让我们测试一下这个过程:@Value("${person2.name:null}")privateStringname;@Value("${person2.gender:null}")privateStringgender;@GetMapping("fcTest2")publicvoidymlProFctest2(){System.out.println(名称);System.out.println(gender);}先调用fcTest接口,再调用fcTest2接口会打印一个空值:nullnull解决这个问题也很难简单,可以配合PropertySourcesPlaceholderConfigurer使用,它实现了BeanFactoryPostProcessor接口,即一个bean工厂后处理器的实现,可以将配置文件的属性值加载到一个Properties文件中。使用方法如下:@ConfigurationpublicclassPropertyConfig{@BeanpublicstaticPropertySourcesPlaceholderConfigurerplaceholderConfigurer(){PropertySourcesPlaceholderConfigurerconfigurer=newPropertySourcesPlaceholderConfigurer();YamlPropertiesFactoryBeanyamlProFb=newYamlPropertiesFactoryBean();yamlProFb.setResources(newClassPathResource("application2.yml"));配置器.setProperties(yamlProFb.getObject());返回配置器;}}再次调用之前的接口,结果如下,可以正常获取到application2.yml中的属性:.用法非常相似:@GetMapping("fcMapTest")publicvoidymlMapFctest(){YamlMapFactoryBeanyamlMapFb=newYamlMapFactoryBean();yamlMapFb.setResources(newClassPathResource("application2.y"));Mapmlmap=yamlMapFb.getObject();System.out.println(map);}打印结果:{person2={name=susan,gender=female,age=18}}3.监听事件在前面介绍原理的文章中,我们知道SpringBoot是通过监听事件来加载和解析yml文件的,所以我们也可以按照这种模式来加载自定义配置文件首先,定义一个实现ApplicationListener接口的类。监听的事件类型为ApplicationEnvironmentPreparedEvent,构造方法中传入需要解析的yml文件名:publicYmlListener(StringymlFilePath){this.ymlFilePath=ymlFilePath;}//...}接口的onApplicationEvent()方法需要在自定义监听器中实现,当监听到ApplicationEnvironmentPreparedEvent事件时会触发:@OverridepublicvoidonApplicationEvent(ApplicationEnvironmentPreparedEventevent){ConfigurableEnvironmentenvironment=event.getEnvironment();ResourceLoader加载器=newDefaultResourceLoader();YamlPropertySourceLoaderymlLoader=newYamlPropertySourceLoader();尝试{List>sourceList=ymlLoader.load(ymlFilePath,loader.getResource(ymlFilePath));对于(PropertySourcepropertySource:sourceList){environment.getPropertySources().addLast(propertySource);}}catch(IOExceptione){e.printStackTrace();}}上述代码中,主要实现是:获取当前环境Environment,当ApplicationEnvironmentPreparedEvent事件被触发时,Environment已经加载完毕,可以通过YamlPropertySourceLoader获取event事件,加载并解析配置文件。将解析后的OriginTrackedMapPropertySource添加到Environment中修改启动类,并在启动类中添加这个监听器:publicstaticvoidmain(String[]args){SpringApplicationapplication=newSpringApplication(MyApplication.class);application.addListeners(newYmlListener("classpath:/application2.yml"));application.run(args);}在环境中添加propertySource前打断点,查看环境变化:执行完成最后可以看到环境中添加了配置文件源:启动完成后调用接口,查看结果:susanfemale可以正确获取到配置文件中的值,说明自定义监听器已经生效4.之前SnakeYml引入的几个方法在Spring环境下可以完成,不需要引入其他依赖。接下来要介绍的SnakeYml使用前需要引入依赖,但也可以脱离Spring环境独立使用。首先引入依赖坐标:org.yamlsnakeyaml1.23准备一个yml配置文件:person1:name:hydragender:maleperson2:name:susan性别:female在使用SnakeYml解析yml时,最常用的方法有load、loadlAll、loadAs。这三个方法可以加载yml文件或者字符串,最后返回解析出来的对象。让我们从基本的加载方法开始:publicvoidtest1(){Yamlyaml=newYaml();Mapmap=yaml.load(getClass().getClassLoader().getResourceAsStream("snake1.yml"));System.out.println(map);}运行上面的代码,打印Map中的内容:{person1={name=hydra,gender=male},person2={name=susan,gender=female}}接下来看loadAll方法,可以用来加载yml中---connectors连接的多个文档,修改上面的yml文件:person1:name:hydragender:male---person2:name:susangender:female添加后connector,尝试使用load方法解析,报错如下,说明发现了另一个yml文件,无法正常解析:此时修改上面代码,使用loadAll方法:publicvoidtest2(){Yamlyaml=newYaml();Iterableobjects=yaml.loadAll(getClass().getClassLoader().getResourceAsStream("snake2.yml"));for(Objectobject:objects){System.out.println(object);}}执行结果如下:{person1={name=hydra,gender=male}}{person2={name=susan,gender=female}}可以看出loadAll方法返回的是一个对象的迭代,而Each对象对应yml中的一个文档,修改后的yml文件被解析成两个独立的Map。接下来我们看一下loadAs方法,它可以在yml解析过程中指定类型,直接封装成一个对象。我们直接复用上面的snake1.yml,在解析前创建两个实体类对象用于接收:@DatapublicclassPerson{SinglePersonperson1;SinglePersonperson2;}@DatapublicclassSinglePerson{字符串名称;Stringgender;}下面使用loadAs方法加载yml。注意该方法的第二个参数是用来封装yml的实体类型。publicvoidtest3(){Yamlyaml=newYaml();Personperson=yaml.loadAs(getClass().getClassLoader().getResourceAsStream("snake1.yml"),Person.class);System.out.println(person.toString());}查看执行结果:Person(person1=SinglePerson(name=hydra,gender=male),person2=SinglePerson(name=susan,gender=female))其实如果想把yml封装成一个entity对象,也有另外一种方法。创建Yaml对象时,传入指定实体类的构造函数对象,然后直接调用load方法实现:publicvoidtest4(){Yamlyaml=newYaml(newConstructor(Person.class));Personperson=yaml.load(getClass().getClassLoader().getResourceAsStream("snake1.yml"));System.out.println(person.toString());}执行结果同上:Person(person1=SinglePerson(name=hydra,gender=male),person2=SinglePerson(name=susan,gender=female))SnakeYml其实实现了很多功能,这里就不一一列举了。感兴趣的朋友可以自行查看文档。如果你看完上一篇文章再去读源码,你会发现,其实在SpringBoot的底层,yml的解析操作也是借助SnakeYml进行的。5.jackson-dataformat-yaml比大家平时用jackson多用来处理json。其实也可以用来处理yml。使用前需要引入依赖:com.fasterxml.jackson.dataformatjackson-dataformat-yaml2.12.3使用jackson读取yml也很简单。这里使用了常用的ObjectMapper。当创建指定ObjectMapper对象时,使用YAML工厂,然后你可以简单地将yml映射到实体:publicvoidread()throwsIOException{ObjectMapperobjectMapper=newObjectMapper(newYAMLFactory());InputStreaminput=newFileInputStream("F:\\Work\\yml\\src\\main\\resources\\snake1.yml");Personperson=objectMapper.readValue(input,Person.class);System.out.println(person.toString());}runResult:Person(person1=SinglePerson(name=hydra,gender=male),person2=SinglePerson(name=susan,gender=female))如果要生成一个yml文件,可以调用ObjectMapper的writeValue方法来实现:publicvoidwrite()throwsIOException{Mapmap=newHashMap<>();单身人士nperson1=newSinglePerson("特兰克斯","男");SinglePersonperson2=newSinglePerson("悟天","男");Personperson=newPerson(person1,person2);map.put("人",人);ObjectMapperobjectMapper=newObjectMapper(newYAMLFactory());objectMapper.writeValue(newFile("F:\\Work\\yml\\src\\main\\resources\\jackson-gen.yml"),map);}查看生成的yml文件,可以看到jackson对string类型严格加了引号,还在文档开头加了yml链接。至于jackson读写yml的其他复杂功能,大家可以自己去摸索使用。小结本文介绍了5种读取yml配置文件的方法。前3个依赖Spring环境,而SnakeYml和Jackson可以独立于环境使用。可以说是对@Value和@ConfigurationProperties注解使用的补充。这些方法的使用场景各不相同,各有各的优势,各有一些特殊的用法。在我们的工作中更多的情况下,我们需要根据具体的用途来选择一种解决方案或者匹配多种组合。使用。好了,希望这次实战可以帮助到大家,我是九头蛇,下篇文章见。