6 ways to read configuration with SpringBoot

1 Overview


By understanding the springboot loading configuration, you can more easily encapsulate the custom Starter.

In SpringBoot, you can use the following 6 ways to read yml and properties configuration:

  1. Use the @Value annotation: read a single configuration from the springboot global configuration file.
  2. Use Environment interface: dynamically obtain configuration through Environment interface. (Encapsulate all yml data into Environment objects)
  3. Use the @ConfigurationProperties annotation: Use the @ConfigurationProperties annotation on the configuration class and specify the prefix for loading the configuration items, and the configuration can be read in batches and injected into the member variables of the custom class. (Custom classes need to provide setter methods)
  4. Use PropertySource annotation: load the properties file configuration, and then use @Value on the field to get the configuration.
  5. The bean that configures the PropertySourcesPlaceholderConfigurer loads the custom yml file and then uses @Value on the field to get the configuration.
  6. Get configuration in Java native way. (IO stream)

Environment preparation:

1. Create a maven project (no archetype template build required)

Insert image description here

2. Introduce dependencies:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>cn.aopmin</groupId>
    <artifactId>springboot-loadconfig</artifactId>
    <version>1.0.0</version>

    <!--父工程-->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.4.5</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <!-- SpringBoot配置元数据的注解处理器,可以让自定义配置实现自动补全和校验功能 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>
        <!-- web起步依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- junit -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.springframework.boot</groupId>
                            <artifactId>spring-boot-configuration-processor</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

3. Write the startup class:

package cn.aopmin;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class LoadConfigApplication {
    
    
    public static void main(String[] args) {
    
    
        SpringApplication.run(LoadConfigApplication.class, args);
    }
}

2. Use @Value annotation to read a single configuration


1. Write application.yml file configuration:

student:
  name: jack
  age: 20

Insert image description here

2. Use @Value to read the configuration:

@SpringBootTest
@Slf4j
public class ValueTest {
    
    

    @Value("${student.name}")
    private String name;

    @Value("${student.age}")
    private Integer age;

    @Test
    public void test() {
    
    
    log.info("@Value 配置获取 name:{},age:{}",name,age);
    }
}

Insert image description here


Notes on @Value:

@Value annotation can only read a single configuration for assignment, and cannot read the entire configuration file for batch assignment. When using the @Value annotation to read the configuration, make sure the configuration exists in the yml, otherwise an error will be reported when starting the program. The attribute name reference in the annotation is as follows:

@Value("${一级属性名.二级属性名...}")

② When using the @Value annotation to reference an attribute, you can add a default value in the form of a colon (:default-value) after the attribute name. This way, if the corresponding property is not found in the configuration file, the default value will be used. If the property is found in the configuration file, its value will override the default value.

//可以使用各种类型的默认值,包括字符串、数字、布尔值等
@Value("${student.name:aopmin}")
private String name;

@Value("${student.age:18}")
private Integer age;
//表示一个空字符串作为默认值
@Value("${student.name:}")
private String name;

@Value annotation can only be used in beans managed by Spring, such as @Component, @Service , @Controller and other annotation-modified classes, or @Configuration classes written using Java configuration.

@Value annotations can be used on fields, constructor parameters, method parameters and methods. When you put it on a method, the method is called when the Spring container is initialized, passing the value of the configuration property as a parameter to the method.

@Component
public class MyBean {
    
    

    private String myProperty;

    @Autowired
    public MyBean(@Value("${my.property}") String myProperty) {
    
    
        this.myProperty = myProperty;
    }

    @Value("${another.property}")
    public void setAnotherProperty(String anotherProperty) {
    
    
        // do something with anotherProperty...
    }

    @Value("${yet.another.property}")
    public void processValue(String value) {
    
    
        // do something with value...
    }
    
}

/*
@Value注解被用于构造函数参数、setter方法和普通方法上。容器初始化时,会将配置属性的值作为参数传递到构造函数、setter方法和普通方法中。
*/

@Value annotation cannot be used on fields modified by static. Because the @Value annotation parses the property value and injects it into the target field by accessing the context in the Spring container. Since the static field does not belong to the object instance and cannot access the container through the instance, using the @Value annotation on the static field is invalid.

Insert image description here


3. Use @ConfigurationProperties annotation for batch binding


1. Write application.yml file configuration:

student:
  name: jack
  age: 20

2. Use @ConfigurationProperties to bind in batches:

package cn.aopmin.pojo;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

/**
 * 参数配置类   (需要提供setter方法)
 *
 * @author 白豆五
 * @version 2023/07/16
 * @since JDK8
 */

@Component
@Data
//将这个类与配置文件前缀为student的配置绑定,然后把yml、properties中关于student的配置信息注入到当前类的成员变量中
@ConfigurationProperties(prefix = "student")
public class StudentProperties {
    
    
    private String name;
}

3. Test

@SpringBootTest
public class ConfigurationPropertiesTest {
    
    

    @Autowired
    private StudentProperties studentProperties;

    @Test
    public void test() {
    
    
        System.out.println("读取配置: name==="+studentProperties.getName());
    }
}

Insert image description here

Notes on @ConfigurationProperties:

  1. Make sure the @EnableConfigurationProperties annotation is added: In order for @ConfigurationProperties to take effect, you need to add the @EnableConfigurationProperties (value=xxxxProperties.class) annotation to the main configuration class and enable the @ConfigurationProperties annotation automatic assembly function.
  2. Mapping rules for property names in configuration files and class field names: By default, @ConfigurationProperties will map property names and class field names in the configuration file. For example, the attribute student.name in the configuration file is automatically mapped to the class field name. If the attribute name in the configuration file is inconsistent with the class field name, you can use the @Value annotation or setter method to specify the mapping relationship.
  3. The class must be a Spring-managed bean: The class marked by the @ConfigurationProperties annotation must be a bean managed by the Spring container, so you need to ensure that the class is marked by @Component or other related annotations so that Spring can scan and create instances of the class.
  4. Support type conversion: @ConfigurationProperties supports automatic type conversion to convert the string value in the configuration file to the type of the target field. For example, convert strings to integers, booleans, etc. If the type conversion cannot be performed, an exception will be thrown.
  5. Default values ​​and optional properties: Default values ​​can be set for fields annotated with @ConfigurationProperties to prevent the corresponding properties from being missing in the configuration file. You can use the ":" symbol to specify a default value, such as @Value("${my.property:default-value}"). In addition, you can use the required attribute to specify whether a property is required.
  6. Verification and verification of configuration items: You can use the annotations of the JSR-303/349 specification to verify and verify the fields annotated with @ConfigurationProperties. For example, use @NotBlank, @Min, @Max and other annotations to limit the validity of attribute values.

4. Use Environment to dynamically obtain configuration


1. Write application.yml file configuration:

student:
  name: jack
  age: 20

2. Use Environment to dynamically obtain configuration: (Automatically assemble the Environment object, and then call the getProperty() method to obtain the specified property value)

package cn.aopmin.test;

import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.core.env.Environment;

import javax.annotation.Resource;

/**
 * Environment是springboot核心的环境配置接口,它提供了一些方法用于访问应用程序配置属性。
 * 包括系统属性、操作系统环境变量、命令行参数、以及配置文件中定义的属性等等
 *
 * @author 白豆五
 * @version 2023/07/16
 * @since JDK8
 */
@Slf4j
@SpringBootTest
public class EnvironmentTest {
    
    

    @Resource
    private Environment env;

    @Test
    public void test() {
    
    
        String name = env.getProperty("student.name");
        // 逻辑处理...(也可以控制某一个bean是否生效)
        log.info("Environment配置读取: name:{}", name);
    }}

In addition to automatic assembly, beans can also be obtained from the spring container:

@Slf4j
@SpringBootTest
public class EnvironmentTest2 implements EnvironmentAware {
    
    

    private Environment env;

    @Test
    public void test() {
    
    
        String name = env.getProperty("student.name");
        log.info("Environment配置读取: name:{}", name);
    }

    @Override
    public void setEnvironment(Environment environment) {
    
    
        // 逻辑处理...(也可以控制某一个bean是否生效)
        this.env = environment;
    }
}

Aware is a set of special interfaces provided by the Spring framework, which allows beans to get some resource information from the Spring container.

Insert image description here

The Aware interface is a callback mechanism. When a Bean is instantiated and registered in the Spring container, the container will automatically call the method in the Bean that implements the specific Aware interface and pass the corresponding resources or information to the Bean.

The following are several commonly used Aware interfaces:

  • ApplicationContextAware: By implementing this interface, the Bean can access the ApplicationContext object to obtain relevant information about the Spring container.

  • BeanFactoryAware: By implementing this interface, Bean can access the BeanFactory object to obtain relevant information about the Bean in the container.

  • EnvironmentAware: By implementing this interface, Beans can access the Environment object to obtain environment-related configuration properties, such as system properties, environment variables, etc.

  • ResourceLoaderAware: By implementing this interface, the Bean can access the ResourceLoader object to obtain the resource loader for loading resource files under the class path.

  • MessageSourceAware: By implementing this interface, the Bean can access the MessageSource object to obtain internationalized messages.


5. Use @PropertySources annotation to obtain external configuration


The first three types all obtain the configuration from the springboot global configuration file. It is not possible to obtain external custom files. We can obtain the ==.properties== file configuration through the @PropertySources annotation.

1. Create the student.properties file in the resources directory:

student.id=1001
student.name=白豆五

2. Use the @PropertySources annotation in the configuration class to bind the configuration:

package cn.aopmin.pojo;

import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;

/**
 * 绑定自定义properties配置
 *
 * @author 白豆五
 * @version 2023/07/16
 * @since JDK8
 */
@Data
@Configuration
@PropertySource(value = "classpath:student.properties", encoding = "UTF-8")
public class PropertySourcesConf {
    
    
    @Value("${student.id}")
    private Integer id;
    @Value("${student.name}")
    private String name;
}

3. Test

@SpringBootTest
@Slf4j
public class PropertySourcesTest {
    
    

    @Resource
    private PropertySourcesConf propertySourcesConf;

    @Test
    public void test() {
    
    
       log.info("PropertySources配置读取 id: {}", propertySourcesConf.getId());
            log.info("name: {}", propertySourcesConf.getName());
    }
}

Insert image description here


6. Configure the Bean of PropertySourcesPlaceholderConfigurer to obtain external configuration


1. Write student.yml configuration:

file:
  type: 自定义yaml文件配置

2. Configure PropertySourcesPlaceholderConfigurer to obtain custom yml file configuration:

package cn.aopmin.config;

import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.core.io.ClassPathResource;

import java.util.Objects;

/**
 * 配置PropertySourcesPlaceholderConfigurer读取yml配置
 * @author 白豆五
 * @version 2023/07/16
 * @since JDK8
 */
@Configuration
public class MyYamlConfig {
    
    

    @Bean
    public static PropertySourcesPlaceholderConfigurer yamlConfigurer() {
    
    
        PropertySourcesPlaceholderConfigurer configurer = new PropertySourcesPlaceholderConfigurer();
        YamlPropertiesFactoryBean yaml = new YamlPropertiesFactoryBean();
        yaml.setResources(new ClassPathResource("student.yml"));//自定义yml文件
        //Objects.requireNonNull()方法的作用是如果对象为空,则抛出空指针异常,否则返回对象本身。
        configurer.setProperties(Objects.requireNonNull(yaml.getObject()));
        return configurer;
    }
}

3. Test

@SpringBootTest
public class LoadYamlTest {
    
    
    
    @Value("${file.type}")
    private String fileType;

    @Test
    public void test() {
    
    
        System.out.println("读取yaml配置:"+fileType);
    }
}

Insert image description here


7. Obtain configuration in Java native way


Read the configuration through the IO stream and then put it into the properties configuration object.

package cn.aopmin.test;

import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.Properties;

/**
 * @author 白豆五
 * @version 2023/07/16
 * @since JDK8
 */
@SpringBootTest
public class CustomTest {
    
    


    @Test
    public void test() {
    
    
        // 配置对象
        Properties props = new Properties();
        InputStreamReader input = null;
        try {
    
    
            // 输入流 (字节流转字符流)
            input = new InputStreamReader(
                    this.getClass().getClassLoader().getResourceAsStream("student.properties"),//通过类加载器来获取指定路径下的资源文件,并返回一个InputStream对象
                    StandardCharsets.UTF_8); //指定编码格式

            // 加载配置
            props.load(input);
        } catch (IOException e) {
    
    
            throw new RuntimeException(e);
        } finally {
    
    
            if (input!=null)
                try {
    
    
                    input.close();
                } catch (IOException e) {
    
    
                    e.printStackTrace();
                }

        }
        // 获取配置
        System.out.println("id:" + props.getProperty("student.id") + ", name:" + props.getProperty("student.name"));
    }
}

Insert image description here

Guess you like

Origin blog.csdn.net/qq_46921028/article/details/131755191