• notice
  • Congratulations on the launch of the Sought Tech site

5 kinds of high-level yml file reading methods, do you know?

In the previous article, we analyzed the whole process of SpringBoot resolution yml configuration file from the perspective of source code, then we will do some actual combat today and summarize the @Value of the bad street.In addition to @ConfigurationProperties, what other methods can be used to read the content of the yml configuration file,

1, Environment

There is a class Environment in Spring, which can be considered as the environment in which the current application is running.It inherits the PropertyResolver interface, so it can be used as a property resolution To use it, first create a yml file with the following attributes:

person:
  name: hydra
  gender: male
  age: 18

It is also very simple to use.You can directly use @Autowired to inject into the class to be used, and then call its getProperty() method to get the property name according to the property name.Take out the corresponding value,

@RestController
public class EnvironmentController {
    @Autowired
    private Environment environment;

    @GetMapping("envTest")
    private void getEnv(){
        System.out.println(environment.getProperty("person.name"));
        System.out.println(environment.getProperty("person.gender"));

        Integer autoClose=environment
           .getProperty("person.age", Integer.class);
        System.out.println(autoClose);
        String defaultValue=https://www.cnblogs.com/trunks2008/p/environment
           .getProperty("person.other", String.class, "defaultValue");
        System.out.println(defaultValue);
    }
}

As can be seen in the above example, in addition to simple acquisition, the method provided by Environment can also perform type conversion on the retrieved attribute value and set the default value.Call the above interface, the print result is as follows:

hydra
male
18
defaultValue

In addition to obtaining properties, it can also be used to determine the active configuration file.We first activate the pro file in application.yml:

spring:
  profiles:
    active: pro

You can use the acceptsProfiles method to detect whether a certain profile is activated and loaded, or use the getActiveProfiles method to get all activated profiles.Test the interface:

@GetMapping("getActiveEnv")
private void getActiveEnv(){
    System.out.println(environment.acceptsProfiles("pro"));
    System.out.println(environment.acceptsProfiles("dev"));

    String[] activeProfiles=environment.getActiveProfiles();
    for (String activeProfile : activeProfiles) {
        System.out.println(activeProfile);
    }
}

Print results:

true
false
pro

2.YamlPropertiesFactoryBean

In Spring, you can also use YamlPropertiesFactoryBean to read the yml file of the custom configuration, instead of being constrained by application.yml and other activated configurations file,

In the application program, you only need to set the save path of the custom yml configuration file through the setResources() method, and then obtain the through the getObject() method Properties object, you can use it to get specific properties later, let's see an example:

@GetMapping("fcTest")
public void ymlProFctest(){
    YamlPropertiesFactoryBean yamlProFb=new YamlPropertiesFactoryBean();
    yamlProFb.setResources(new ClassPathResource("application2.yml"));
    Properties properties=yamlProFb.getObject();
    System.out.println(properties.get("person2.name"));
    System.out.println(properties.get("person2.gender"));
    System.out.println(properties.toString());
}

View the running result, you can read the content of the specified application2.yml:

susan
female
{person2.age=18, person2.gender=female, person2.name=susan}

But there is a problem with this use, that is, the value of this property can only be obtained in the request of this interface.If you write another interface, you do not use YamlPropertiesFactoryBean to read the configuration file , even if the previous method has read the yml file once, the second interface still gets a null value, let's test this program:

@Value("${person2.name:null}")
private String name;
@Value("${person2.gender:null}")
private String gender;

@GetMapping("fcTest2")
public void ymlProFctest2(){
    System.out.println(name);
    System.out.println(gender);
}

The fcTest interface is called once, and the null value will be printed when calling the fcTest2 interface:

null
null

It is also very simple to solve this problem.It can be used with PropertySourcesPlaceholderConfigurer, which implements the BeanFactoryPostProcessor interface, which is the implementation of a bean factory post processor , you can load the property values ​​of the configuration file into a Properties file, using the following methods:

@Configuration
public class PropertyConfig {
    @Bean
    public static PropertySourcesPlaceholderConfigurer placeholderConfigurer() {
        PropertySourcesPlaceholderConfigurer configurer
           =new PropertySourcesPlaceholderConfigurer();
        YamlPropertiesFactoryBean yamlProFb
           =new YamlPropertiesFactoryBean();
        yamlProFb.setResources(new ClassPathResource("application2.yml"));
        configurer.setProperties(yamlProFb.getObject());
        return configurer;
    }
}

Call the previous interface again, the result is as follows, you can get the attributes in application2.yml normally:

susan
female

In addition to using YamlPropertiesFactoryBean to resolve yml to Properties, we can also use YamlMapFactoryBean to resolve yml to Map, the usage is very similar:

@GetMapping("fcMapTest")
public void ymlMapFctest(){
    YamlMapFactoryBean yamlMapFb=new YamlMapFactoryBean();
    yamlMapFb.setResources(new ClassPathResource("application2.yml"));
    Map<String, Object> map=yamlMapFb.getObject();
    System.out.println(map);
}

Print results:

{person2={name=susan, gender=female, age=18}}

3, monitor events

In the previous article introducing the principle, we know that SpringBoot loads and resolves yml files by listening to events, so we can also follow this pattern to load custom configuration files,

First, define a class to implement the ApplicationListener interface, and the monitored event type is ApplicationEnvironmentPreparedEvent, and pass in the name of the yml file to be resolved in the constructor:

public class YmlListener implements
    ApplicationListener<ApplicationEnvironmentPreparedEvent> {
    private String ymlFilePath;
    public YmlListener(String ymlFilePath){
        this.ymlFilePath=ymlFilePath;
    }
   //...
}

The onApplicationEvent() method of the interface needs to be implemented in the custom listener, which will be triggered when the ApplicationEnvironmentPreparedEvent event is monitored:

@Override
public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {
    ConfigurableEnvironment environment=event.getEnvironment();
    ResourceLoader loader=new DefaultResourceLoader();
    YamlPropertySourceLoader ymlLoader=new YamlPropertySourceLoader();
    try {
        List<PropertySource<?>> sourceList=ymlLoader
           .load(ymlFilePath, loader.getResource(ymlFilePath));
        for (PropertySource<?> propertySource : sourceList) {
            environment.getPropertySources().addLast(propertySource);
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}

In the above code, the main implementation is:

  • Get the current environment Environment, when the ApplicationEnvironmentPreparedEvent event is triggered, the loading of the Environment has been completed, and it can pass the event Event Get
  • Load and resolve configuration files through YamlPropertySourceLoader
  • Add the OriginTrackedMapPropertySource to the Environment after the resolution is complete

Modify the startup class and add this listener to the startup class:

public static void main(String[] args) {
    SpringApplication application=new SpringApplication(MyApplication.class);
    application.addListeners(new YmlListener("classpath:/application2.yml"));
    application.run(args);
}

Add a breakpoint before adding propertySource to environment to see the environment changes:

After the execution is complete, you can see that the configuration file source has been added to the environment:

After the startup is completed, call the interface again to view the results:

susan
female

The value in the configuration file can be obtained correctly, indicating that the custom listener has taken effect,

4.SnakeYml

The several methods described above can be completed without introducing other dependencies in the Spring environment.The SnakeYml to be introduced next needs to introduce dependencies before use, but it can also be separated from the Spring environment at the same time.Use alone, first introduce dependent coordinates:

<dependency>
    <groupId>org.yaml</groupId>
    <artifactId>snakeyaml</artifactId>
    <version>1.23</version>
</dependency>

Prepare a yml configuration file:

person1:
  name: hydra
  gender: male
person2:
  name: susan
  gender: female

When using SnakeYml to resolve yml, the most commonly used methods are load, loadlAll, loadAs, These three methods can load yml files or strings, and finally return the resolved object.Let's start with the basic load method:

public void test1(){
    Yaml yaml=new Yaml();
    Map<String, Object> map=
            yaml.load(getClass().getClassLoader()
                   .getResourceAsStream("snake1.yml"));
    System.out.println(map);
}

Run the above code to print the contents of the Map:

{person1={name=hydra, gender=male}, person2={name=susan, gender=female}}

Let's take a look at the loadAll method, which can be used to load multiple files connected by the --- connector in yml, and modify the above yml file :

person1:
  name: hydra
  gender: male
---
person2:
  name: susan
  gender: female

After adding the connector, try to use the load method for resolution, and the error is as follows, showing that another yml file was found and cannot be resolved normally:

At this time, modify the above code and use the loadAll method:

public void test2(){
    Yaml yaml=new Yaml();
    Iterable<Object> objects=
        yaml.loadAll(getClass().getClassLoader()
           .getResourceAsStream("snake2.yml"));
    for (Object object : objects) {
        System.out.println(object);
    }
}

The execution result is as follows:

{person1={name=hydra, gender=male}}
{person2={name=susan, gender=female}}

You can see that the loadAll method returns an iteration of an object, each object in it corresponds to a file in yml, and the modified yml file is resolved into two independent files Map,

Let's take a look at the loadAs method.It can specify the type in the yml resolution program and directly encapsulate it into an object.We directly reuse the above snake1.yml

code>, create two object objects for receiving before the resolution:

@Data
public class Person {
    SinglePerson person1;
    SinglePerson person2;
}

@Data
public class SinglePerson {
    String name;
    String gender;
}

The following uses the loadAs method to load yml, pay attention to the second argument of the method, which is the object type used to encapsulate the yml,

public void test3(){
    Yaml yaml=new Yaml();
    Person person=
        yaml.loadAs(getClass().getClassLoader().
            getResourceAsStream("snake1.yml"), Person.class);
    System.out.println(person.toString());
}

View execution results:

Person(person1=SinglePerson(name=hydra, gender=male), person2=SinglePerson(name=susan, gender=female))

Actually, if you want to encapsulate yml into an object, you can also use another method.When creating a Yaml object, pass in a constructor object of the specified object class, and then directly This can be done by calling the load method:

public void test4(){
    Yaml yaml=new Yaml(new Constructor(Person.class));
    Person person=yaml.load(getClass().getClassLoader().
            getResourceAsStream("snake1.yml"));
    System.out.println(person.toString());
}

The execution result is the same as above:

Person(person1=SinglePerson(name=hydra, gender=male), person2=SinglePerson(name=susan, gender=female))

SnakeYml actually implements a lot of functions, so I won't list them all here.Interested friends can check the file by themselves.If you read the source code after reading the previous article, then You will find that, in fact, at the bottom of SpringBoot, it also uses SnakeYml to perform yml resolution operations,

5, jackson-dataformat-yaml

Compared with people who usually use jackson more often, it is used to process json.In fact, it can also be used to process yml, and dependencies need to be introduced before use:

<dependency>
    <groupId>com.fasterxml.jackson.dataformat</groupId>
    <artifactId>jackson-dataformat-yaml</artifactId>
    <version>2.12.3</version>
</dependency>

It is also very simple to use jackson to read yml.The commonly used ObjectMapper is used here, and the YAML factory is specified when creating the ObjectMapper object.Then you can simply map the yml to the object:

public void read() throws IOException {
    ObjectMapper objectMapper=new ObjectMapper(new YAMLFactory());
    InputStream input=
        new FileInputStream("F:\\Work\\yml\\src\\main\\resources\\snake1.yml");
    Person person=objectMapper.readValue(input, Person.class);
    System.out.println(person.toString());
}

Run result:

Person(person1=SinglePerson(name=hydra, gender=male), person2=SinglePerson(name=susan, gender=female))

If you want to generate a yml file, you can call the writeValue method of ObjectMapper to implement:

public void write() throws IOException {
    Map<String,Object> map=new HashMap<>();
    SinglePerson person1=new SinglePerson("Trunks", "male");
    SinglePerson person2=new SinglePerson("Goten", "male");
    Person person=new Person(person1,person2);
    map.put("person",person);

    ObjectMapper objectMapper=new ObjectMapper(new YAMLFactory());
    objectMapper
           .writeValue(new File("F:\\Work\\yml\\src\\main\\resources\\jackson-gen.yml"),map);
}

Looking at the generated yml file, you can see that jackson has strictly added quotation marks to the string type, and also added a yml link at the beginning of the file.As for other complex functions of jackson reading and writing yml, you can refer to the homework to explore and use it by yourself,

Summary

This article introduces 5 ways to read yml configuration files, the first 3 rely on the Spring environment, while SnakeYml and Jackson can be used independently from the environment, It can be said that they are supplements to the @Value and @ConfigurationProperties annotations.These methods are used in different scenarios and have their own advantages, each with some special features.usage, and in more cases in our homework, we need to select a scheme or use multiple combinations according to specific purposes,

Okay, I hope this actual combat can help you, I am Hydra, see you in the next part,

Tags

Technical otaku

Sought technology together

Related Topic

1 Comments

author

atorvastatin 20mg usa & lt;a href="https://lipiws.top/"& gt;buy generic atorvastatin& lt;/a& gt; lipitor 20mg for sale

Znwcop

2024-03-10

Leave a Reply

+