@ConfigurationProperties in Spring Boot

There are number of ways you can externalize your configuration properties in application so that you can work in different environment. You can use properties files, YAML files, environment variables, and command-line arguments to externalize configuration. Property values can be injected directly into your beans by using the @Valueannotation but that is very tedious and cumbersome process , especially if you are working with multiple properties or your data is hierarchical in nature.

Type-safe Configuration Properties

Spring gives you another alternative option so that you can use those properties in Spring Bean fashion. As shown in below example.

Implementation: –

@Configuration
@ConfigurationProperties(prefix = "db")
public class ApplicationConfig {
 
  private String className;
  private String name;
  private int port;
  private String userName;
  private String password;
 
  //setter/getters
 
}

The above POJO class can be defined in the following properties

#Simple Properties
db.className=com.mysql.jdbc.Driver
db.name=schooldb
db.port=7678
db.userName=schoolmaster
db.password=hispassword

Getters and setters are usually mandatory, since binding is through standard Java Beans property descriptors, just like in Spring MVC. A setter may be omitted in the following cases:

  • Maps, as long as they are initialized, need a getter but not necessarily a setter, since they can be mutated by the binder.
  • Collections and arrays can be accessed either through an index (typically with YAML) or by using a single comma-separated value (properties). In the latter case, a setter is mandatory. We recommend to always add a setter for such types. If you initialize a collection, make sure it is not immutable (as in the preceding example).
  • If nested POJO properties are initialized (like the Security field in the preceding example), a setter is not required. If you want the binder to create the instance on the fly by using its default constructor, you need a setter.

There could be lots of way to implement ApplicationConfig but below is the one which we have followed. We have created one simple Rest Controller and trying to access configuration properties. i.e.

@RestController
@RequestMapping("/api")
public class MyController {
 
@Autowired
private ApplicationConfig applicationConfig;
 
   @GetMapping("/config")
   public String getMethod() {
      String values = "ClassName:-" + applicationConfig.getClassName()
            + ", Database - " 
            + applicationConfig.getDb()
            + ", Port: - " 
            + applicationConfig.getPort()
            + ", User Name: - " 
            + applicationConfig.getUserName()
            + ", Password: - " 
            + applicationConfig.getPassword();
 
    return "Hello- " + values;
   }
}

And if you hit this api the outcome will be something like below image.

Third-party Configuration

Using @ConfigurationProperties to annotate a class, as well as we can also use it on public @Bean methods. Like below

@Configuration
public class ApplicationConfig {
    @ConfigurationProperties(prefix = "another")
    @Bean
    public MyBean getMyBean() {
        return new MyBean();
    }
}

And the same properties can be declared in property file as below.

another.value1=value1
another.value2=value2

And some where in your other class. MyBeam can be injected and used like below.

@Autowired
private MyBean myBean;
 
@GetMapping("/app-config")
public String getApplicationConfig() {
    String values = "Value1:-" + myBean.getValue1()
            + ", Value2 - " + myBean.getValue1();
 
    return "Hello- " + values;
}

And if you hit this api, you will get the result like.

Relaxed Binding

Spring Boot uses some relaxed rules for binding Environment properties to @ConfigurationProperties beans, so there does not need to be an exact match between the Environment property name and the bean property name. Common examples where this is useful include dash-separated environment properties (for example, context-path binds to contextPath), and capitalized environment properties (for example, PORT binds to port).

For example, consider the following @ConfigurationProperties class:

@Configuration
@ConfigurationProperties(prefix = "db")
public class ApplicationConfig {
 
  private String className;
  private String name;
  private int port;
  private String userName;
  private String password;
 
  //setter/getters
 
}

In the above example, the following properties names can all be used:

Property
db.userName
db.user_name
db.user-name etc

Merging Complex Types

You may have List of some type, example below.

@ConfigurationProperties("myprop")
public class MyBeanProperties {
 
   private final java.util.List<MyBean> list = new ArrayList<MyBean>();
 
   public java.util.List<MyBean> getList() {
        return list;
   }
}

Consider the following configuration for above code

myprop:
  list:
    - value1: my name
      value2: my description

Since we have list in our class. So to have multiple values MyBean lets have below values in yml file

myprop:
  list:
    - value1: my name1
      value2: my description1
    - value1: my name 2
      value2: my description 2

Same goes for Map like below.

@Configuration
@ConfigurationProperties("myprop")
public class MyBeanProperties {
 
   private final Map<String, MyBean> beanMap = new HashMap<>();
 
   public Map<String, MyBean> getBeanMap() {
       return beanMap;
   }
}

And below code will go in yml file

mymapprop:
  beanMap:
    key1:
      value1: my name1
      value2: my description1		
    key2:
      value1: my name2
      value2: my description2

Hope this must have cleared your some of doubts about @ConfigurationProperties.

The above code can be found in Github

Advertisements