Spring Boot属性文件:@ConfigurationProperties示例

时间:2020-01-09 10:44:31  来源:igfitidea点击:

如果我们在应用程序中使用一些配置参数,那么最好是外部化配置,而不是硬编码值。在Spring Boot中,外部化配置的一种方法是使用属性文件或者YAML文件。在本文中,我们将介绍如何在Spring Boot中使用属性文件以及如何从属性文件中读取属性值。

Spring Boot application.properties文件

在Spring Boot中,SpringApplication自动从application.properties文件加载属性,并将其添加到Spring Environment。我们应该将application.properties文件保存在以下位置之一。

1.当前目录的/ config子目录
2.当前目录
3.一个classpath / config包
4. classpath根

该列表按优先级排序(在列表较高位置定义的属性将覆盖在较低位置定义的属性)。

请注意,我们还可以使用YAML(.yml)文件代替" .properties"文件。

创建application.properties文件

在src / main / resources目录中创建application.properties文件,因为该属性文件应位于类路径中。

将一些键值对添加到application.properties文件。

springboot.app.name=SpringBootProject
springboot.welcome.message=Welcome User

使用YAML文件

我们也可以在同一位置创建application.yml文件而不是application.properties。 YAML是JSON的超集,它是用于指定层次结构配置数据的便捷格式。

示例application.yml文件

springboot:
	app:
		name:SpringBootProject
	welcome:
		message:Welcome User

切换到另一个文件名

如果要将配置文件命名为application.properties以外的名称,则可以通过指定spring.config.name环境属性来实现。

java -jar SpringBootProject.jar --spring.config.name=myprops

我们还可以通过使用spring.config.location环境属性来引用显式位置

java -jar SpringBootProject.jar --spring.config.location=classpath:/default.properties, classpath:/override.properties

使用@Value注释注入配置值

准备好属性文件后,即可在Spring Bean中使用它。从属性中注入属性值的一种方法是使用@Value注释。使用@Value注释,我们可以读取环境变量或者系统变量。
这是一个类,其中在字段上使用@Value注释,以通过使用属性的键来注入属性值。

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component
public class WelcomeConfiguration {
  @Value("${springboot.app.name}")
  private String name;
  @Value("${springboot.welcome.message}")
  private String message;
  public String getName() {
    return name;
  }
  public void setName(String name) {
    this.name = name;
  }
  public String getMessage() {
    return message;
  }
  public void setMessage(String message) {
    this.message = message;
  }
}

我们可以使用以下应用程序类对其进行测试。

import org.netjs.SpringBootApp.controller.WelcomeConfiguration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringBootAppApplication  implements CommandLineRunner{
  @Autowired
  WelcomeConfiguration config;
  public static void main(String[] args) {
    SpringApplication.run(SpringBootAppApplication.class, args);
  }

  @Override
  public void run(String... args) throws Exception {
    // displaying property values
    System.out.println("Application Name- " + config.getName());
    System.out.println("Welcome Message- " + config.getMessage());
  }
}

输出:

Application Name- SpringBootProject
Welcome Message- Welcome User

使用@ConfigurationProperties注释的应用程序配置

如果我们具有多个属性或者数据本质上是分层的,则使用@Value(" $ {property}")注释来注入配置属性将变得乏味。 Spring Boot提供了更好的替代@ConfigurationProperties注释,以从属性文件读取配置值。

要了解如何使用@ConfigurationProperties从Spring Boot应用程序的属性文件中读取值,请创建src / main / resources / application.properties文件,该文件具有不同数据类型的值,并且本质上也是分层的。

springboot.app.name=SpringBootProject
springboot.app.creator=theitroad
springboot.app.active=true
springboot.app.pages=4
#List
springboot.app.citycodes=US,IN,CN,AU

#-- Nested Properties-
springboot.app.inner.strproperty=test
#List
springboot.app.inner.datalist[0]=list0
springboot.app.inner.datalist[1]=list1
#Map
springboot.app.inner.propmap.key1=value1
springboot.app.inner.propmap.key2=value2
springboot.app.inner.propmap.key3=value3

接下来是使用@ConfigurationProperties注释进行注释的类,该类是用于外部化配置的注释,并绑定来自.properties或者YAML文件的某些外部属性。

import java.util.List;
import java.util.Map;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@Component
@ConfigurationProperties(prefix="springboot.app")
public class WelcomeConfiguration {
  private String name;
  private String creator;
  private boolean active;
  private int pages;
  private List<String> cityCodes;
  private final Inner inner = new Inner();

  public static class Inner{
    private String strProperty;
    private List<String> dataList;
    private Map<String, String> propMap;
    
    public void setStrProperty(String strProperty) {
      this.strProperty = strProperty;
    }
    //.. getters and setters
  }
  public String getName() {
    return name;
  }
  public Inner getInner() {
    return inner;
  }
  //.. getters and setters
}

这里要注意的几点是

  • 使用前缀元素,我们可以指定可以绑定到POJO的属性。它还可以照顾到分层属性(如示例中的静态内部类所做的那样)。

  • 属性值绑定以类型安全的方式完成。正如我们在POJO类中看到的那样,存在不同类型的字段String,boolean,int,List,Map,所有这些字段都是通过将属性转换为必需的类型来绑定的。

  • 即使属性文件中的键全部为小写,也已正确绑定到POJO类中的驼峰对应。

SpringBootApplication类

使用下面的类,我们可以显示绑定的属性。

import org.netjs.SpringBootApp.controller.WelcomeConfiguration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringBootAppApplication  implements CommandLineRunner{
  @Autowired
  WelcomeConfiguration config;
  public static void main(String[] args) {
    SpringApplication.run(SpringBootAppApplication.class, args);
  }

  @Override
  public void run(String... args) throws Exception {
    // displaying property values
    System.out.println("Application Name- " + config.getName());
    System.out.println("Creator- " + config.getCreator());
    System.out.println("Active- " + config.isActive());
    System.out.println("Pages- " + config.getPages());
    System.out.println("Codes- " + config.getCityCodes());
    
    System.out.println("Strporoperty- " + config.getInner().getStrProperty());
    System.out.println("Data List- " + config.getInner().getDataList());
    System.out.println("Prop Map- " + config.getInner().getPropMap());
  }
}

输出:

Application Name- SpringBootProject
Creator- theitroad
Active- true
Pages- 4
Codes- [US, IN, CN, AU]
Strporoperty- test
Data List- [list0, list1]
Prop Map- {key1=value1, key2=value2, key3=value3}

@ConfigurationProperties验证

每当使用Spring的@Validated注释对@ConfigurationProperties类进行注释时,Spring Boot就会尝试对其进行验证。支持JSR-303 javax.validation,并且可以使用JSR-303 javax.validation约束
注释直接在配置类上。

添加spring-boot-starter-validation以在类路径上获得兼容的JSR-303实现。

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-validation</artifactId>
</dependency>

在字段上添加@Validated注释和验证约束。

import java.util.List;
import java.util.Map;
import javax.validation.Valid;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import org.springframework.validation.annotation.Validated;

@Component
@ConfigurationProperties(prefix="springboot.app")
@Validated
public class WelcomeConfiguration {
  @NotNull
  private String name;
  private String creator;
  private boolean active;
  private int pages;
  @NotEmpty
  private List<String> cityCodes;
  //it’s good practice to annotate the nested properties
  // associated field as @Valid
  @Valid
  private final Inner inner = new Inner();

  public static class Inner{
    @Size(min = 10, max = 20)
    private String strProperty;
    private List<String> dataList;
    private Map<String, String> propMap;
    //getters and setters
  }
  //getters and setters
}

现在,如果从应用程序属性文件中删除了城市代码,并且strProperty字段的值是" test"(根据值的验证长度,该值应在10到20的范围内),则我们将收到以下错误消息。

***************************
APPLICATION FAILED TO START
***************************

Description:

Binding to target org.springframework.boot.context.properties.bind.BindException: Failed to bind properties under 'springboot.app' to org.netjs.SpringBootApp.controller.WelcomeConfiguration failed:

    Property: springboot.app.inner.strProperty
    Value: test
    Reason: size must be between 10 and 20

    Property: springboot.app.cityCodes
    Value: []
    Reason: must not be empty

Action:

Update your application's configuration