Spring Boot 配置文件属性注入

不需要配置文件场景下的属性注入

@Value注解可以在不需要配置文件的情况下注入属性,经常会看到两种写法 ${}#{}

${properties名称}的表示获取properties的值,注入配置文件中的属性的值。

#{表达式} 括号里面的表达式必须是SpEL表达式的格式。通过 #{表达式} 方式可以在不需要使用配置文件的情况下,动态的将外部值注入到bean中。

@Component
@ToString
public class InjectWithoutConfigurationFile {

  // 注入普通字符串
  @Value("diego")
  private String name;

  // 注入表达式
  @Value("#{T(java.lang.Math).random()}")
  private double random;

  // 注入系统属性
  @Value("#{systemProperties['os.name']}")
  private String defaultLocale;

  // 注入其他bean的属性值
  @Value("#{rectangle.length}")
  private int rectangleLength;

  // 注入url
  @Value("http://www.baidu.com")
  private Resource baiduUrls;

}

测试结果:

InjectWithoutConfigurationFile(name=diego, random=0.20947710881441184, defaultLocale=Mac OS X, rectangleLength=20, baiduUrls=URL [http://www.baidu.com])

配置文件中的属性注入

在Spring Boot项目中,先在全局配置文件中配置好属性值,在项目启动时这些属性自动注入到对应bean对应属性中。

全局配置文件:

  • application.properties
  • application.yaml

这两个都是全局配置文件,但properties的优先级高于yaml,当两个文件中对统一属性配置不同的值时,以properties文件中的为准,两个文件中的不同配置互补。

实现配置文件中的属性自动注入有一下几种方式:

@Value的${}方式

value.from.file=Value got from the file
priority=Properties file
listOfValues=A,B,C
@ToString
@Component
public class Properties {

  @Value("${value.from.file}")
  private String valueFromFile;
  
  @Value("${priority}")
  private String prioritySystemProperty;

  @Value("${listOfValues}")  
  private String[] valuesArray; // 注入数组
}

在测试中如果将listOfValues卸载yaml配置文件中,形如下面的样子,再用@Value("${listOfValues}") 注入的时候会报错。

listOfValues:
	- A
	- B
	- C

在开发过程中,如果需要将配置文件中的单个属性注入bean中,采用@Value是最简单的方式。当然@Value注解也可以将object注入,但总觉得操作有限。

@ConfigurationProperties

当配置文件中的object很复杂时,选用@ConfigurationProperties将object注入会很方便。@ConfigurationProperties注解的使用也有好几种方式,这里主要介绍两种:

  1. Spring Boot 2中,可以使用@ConfigurationProperties和@ConfigurationPropertiesScan两个注解实现配置注入。

    mail:
      hostname: [email protected]
      port: 9000
      from: [email protected]
      defaultRecipients:
        - [email protected]
        - [email protected]
      additionalHeaders:
        redelivery: true
        secure: true
        p3: value
    
    @SpringBootApplication
    @ConfigurationPropertiesScan("com.yang.config")
    public class ConfigApplication {
    
      public static void main(String[] args) {
        SpringApplication.run(ConfigApplication.class, args);
      }
    }
    
    @ConfigurationProperties(prefix = "mail")
    @ToString
    @Setter
    public class ConfigProperties {
    
      private String hostName;
      private int port;
      private String from;
    
      private List<String> defaultRecipients;
      private Map<String, String> additionalHeaders;
    
    }
    

    @ConfigurationPropertiesScan(“com.yang.config”)表示扫描com.yang.config包下的@ConfigurationProperties注解,@ConfigurationProperties(prefix = “mail”)表示将配置文件中前缀为mail的属性与ConfigProperties中的对应的成员变量映射起来。必须为要映射的成员变量创建setter方法,才能将配置文件中的属性值映射成功。

    测试结果:

    ConfigProperties(hostName=host@mail.com, port=9000, from=mailer@mail.com, defaultRecipients=[admin@mail.com, owner@mail.com], additionalHeaders={redelivery=true, secure=true, p3=value})
    
  2. 使用@ConfigurationProperties和@Component注解

    @Component
    @ConfigurationProperties(prefix = "mail")
    @ToString
    @Setter
    public class ConfigProperties {
    
      private String hostName;
      private int port;
      private String from;
    
      private List<String> defaultRecipients;
      private Map<String, String> additionalHeaders;
    
    }
    

    当然还有其他的的注解也能实现复杂的object的注入,我觉得上面这两种使用简单,理解也很容易。

@PropertySource

有时候我们可能会自定义配置文件,专门用来保存某个类的配置,这时需要使用@PropertySource注解先将自定义配置文件加载进来。

# customConfigProperties.properties配置文件

#Simple properties
[email protected]
custom.port=9000
[email protected]

#List properties
custom.defaultRecipients[0][email protected]
custom.defaultRecipients[1][email protected]

#Map Properties
custom.additionalHeaders.redelivery=true
custom.additionalHeaders.secure=true
custom.additionalHeaders.p3=value
@PropertySource("classpath:/customConfigProperties.properties")
@ConfigurationProperties(prefix = "custom")
@Component
@ToString
@Setter
public class CustomConfigProperties {

  private String hostName;
  private int port;
  private String from;

  private List<String> defaultRecipients;
  private Map<String, String> additionalHeaders;
}

可以看出@PropertySource注解将自定义的customConfigProperties.properties配置文件加载进来。之后用@ConfigurationProperties和@Component组合的方式将配置文件的中的object注入。

注:@PropertySource注解不支持加载自定义yaml格式的配置文件。

测试结果:

CustomConfigProperties(hostName=host@mail.com, port=9000, from=mailer@mail.com, defaultRecipients=[admin@mail.com, owner@mail.com], additionalHeaders={redelivery=true, secure=true, p3=value})

实现EnvironmentPostProcessor

EnvironmentPostProcessor接口允许用户在Spring Boot应用启动之前操作 Environment,官方参考资料。

这个链接介绍如何载入和转换自定义的属性到 Environment中,并且最后再访问自定义的属性。

可以用这个接口加载自定义yaml配置文件。

创建自定义配置文件

创建person.yml文件,内容很简单。

personconfig:
  name: lee
  age: 20

实现EnvironmentPostProcessor接口,加载自定义的配置文件。

这段代码来自官方参考文档。

public class PersonConfigProcessor  implements EnvironmentPostProcessor {

  private final YamlPropertySourceLoader loader = new YamlPropertySourceLoader();

  @Override
  public void postProcessEnvironment(ConfigurableEnvironment environment,
                                     SpringApplication application) {
    // 加载自定义的配置文件  
    Resource path = new ClassPathResource("persons.yml"); 
    PropertySource<?> propertySource = loadYaml(path);
    environment.getPropertySources().addLast(propertySource);

  }

  private PropertySource<?> loadYaml(Resource path) {
    if (!path.exists()) {
      throw new IllegalArgumentException("Resource " + path + " does not exist");
    }
    try {
      return this.loader.load("custom-person", path).get(0);
    }
    catch (IOException ex) {
      throw new IllegalStateException("Failed to load yaml configuration from " + path, ex);
    }
  }
}

将接口的实现类注册

PersonConfigProcessor 必须注册到 META-INF/spring.factories 文件中,目的是让Spring Boot在启动时能扫描到这个类,之后才能加载 。

org.springframework.boot.env.EnvironmentPostProcessor=com.yang.config.PersonConfigProcessor

构建要绑定的对象

配置文件的目的就是为将其定义的属性注入到java object中,所以还需要构建一个类用来“接”配置文件定义的内容。

@Component
@ConfigurationProperties(prefix = "personconfig")
@ToString
@Setter
public class PersonConfig {
  private String name;
  private int age;
}

这里的@Setter 不能省略,这种方式也是:先调用无参构造函数构造对象,再调用属性的set方法初始化。使用PersonConfig时,直接装配就可以了。

@Autowired
private PersonConfig personConfig;

测试结果:

PersonConfig(name=lee, age=20)

小结:

  1. 如果不需要配置文件,直接注入,使用 @Value注解。
  2. 用到了配置文件,但注入的都是单个属性值,将要注入的属性写在在 application.properties/application.yml 中,用@Value ${}方式注入。
  3. 用到了配置文件,但注入的是个object,将要注入的object写在 application.properties/application.yml 中,用 @ConfigurationProperties 注入。
  4. 自定义properties配置文件,选用@PropertySource 注入。
  5. 自定义yaml配置文件,选用“实现EnvironmentPostProcessor”的方式注入。

其实,4和5的注入方式都是先将配置文件加载进来,再用@ConfigurationProperties绑定类。只是不同类型的文件,加载的方式不一样。

github

你可能感兴趣的:(Spring,Boot学习笔记,spring,boot,配置文件,自定义,PropertySource,属性)