avatarGain Java Knowledge

Summary

The article advocates for using @ConfigurationProperties over @Value annotations in Spring Boot applications for a more organized and flexible approach to external configuration.

Abstract

The article discusses the drawbacks of using the @Value annotation for injecting properties in Spring applications, emphasizing the lack of separation of concerns and the potential for scattered configuration. It suggests that encapsulating configuration in a dedicated service, such as ConfigurationService, is a better practice for non-Spring Boot applications. For Spring Boot applications, the @ConfigurationProperties annotation is recommended for its ability to externalize configuration in a centralized and maintainable manner. This approach allows for easier validation, combination of property values, and avoids the need for full-text searches to track property usage. The article concludes by highlighting the advantages of @ConfigurationProperties over @Value, including its non-strict nature, support for default values, and the reduction of code clutter.

Opinions

  • The @Value annotation is criticized for leading to disorganized configuration when used extensively across services, controllers, and components.
  • The author believes that configuration should be treated as a separate service within an application to maintain a clear separation of concerns.
  • It is argued that using @ConfigurationProperties provides a more elegant and maintainable way to handle configuration, as it encapsulates properties in a single class.
  • The article suggests that @ConfigurationProperties is more flexible than @Value, as it allows for property validation and combination, and does not require a one-to-one mapping of properties to variables.
  • The author expresses that @ConfigurationProperties is more forgiving, as it does not throw exceptions for missing properties and can provide default values.
  • The preference for @ConfigurationProperties over @Value is justified by the reduced need for full-text searches to find property usage, thus simplifying refactoring and maintenance.

Stop using @value annotation in spring boot.

Configuration is an important topic of every application which has more than a couple of hundred lines of code. In case you are using Spring, you would typically use Spring’s @Value annotation to load values from a Java properties file.

Let’s have a look at the classic @Value annotation in Spring, it may look something like this:

@Service
public class EmployeeServiceImpl implements EmployeeService {

    private static final Logger LOGGER = LoggerFactory.getLogger(EmployeeServiceImpl.class);
    
    @Value("${com.demo.secret-key}")
    private String secretKey;

    @Override
    public List<Employee> getAllEmployee() {
        LOGGER.info("Inside EmployeeServiceImpl getAllEmployee method.");
        LOGGER.info("=====MY Secret Key ===>"+secretKey);
        return null;
    }  
}

The @Value annotation can be used for injecting values into Spring managed beans.

If you do so, Spring would inject the value for the key com.demo.secret-key from your properties file right into your class and you are done. Easy! Maybe too easy.

So what are the disadvantages of this approach?

Here are the some main disadvantages of using this approach. I will discuss here below.

@Value(“${com.demo.secret-key}”) @Value will throw exception if there no matching key in application.properties/yml file. It strictly injects property value.

What will happen when you use this technique through your application? Well, whenever you need some property, you will inject it. You will inject it in services, controllers and components and you will properly inject the same property in different classes. That’s easy and absolutely what the mechanism is about.

However, this means nothing else than scattering your configuration about your whole application. Every class can pick a couple of properties to use. You will have no idea or control which class is using which properties. You will end-up with doing a full text search on your project to find out where a single key is used. You will have a lot of fun if you want to rename one of those keys.

No separation of configuration and service implementation. By using the @Value annotations in our services and beans we are mixing configuration with our service implementation. We want externalized configuration.

Configuration is an service :

Instead of this, configuration should be an encapsulated service of your application such as any other functionality, too. You encapsulate persistence in DAOs, you encapsulate REST services in controllers and you encapsulate security in authenticators. So why not encapsulating configuration?

If you do so, you will have a single point of responsibility to load and get your configuration from. As any other service, you can easily change the implementation. Maybe you don’t want to load your properties from a properties file, but from a database. If you encapsulate your configuration in a service, that’s not a big deal.

@Data
@Service
public class ConfigurationService {

    @Value("${com.demo.secret-key}")
    private String secretKey;

}
@Service
public class EmployeeServiceImpl implements EmployeeService {

    private static final Logger LOGGER = LoggerFactory.getLogger(EmployeeServiceImpl.class);

    @Autowired
    private ConfigurationService configurationService;

    @Override
    public List<Employee> getAllEmployee() {
        LOGGER.info("Inside EmployeeServiceImpl getAllEmployee method.");
        LOGGER.info("=====MY Secret Key ===>"+configurationService.getSecretKey());
        return null;
    }
}

This above approach we can use if we are working with Spring application not Spring boot.

If we are working on Spring Boot application. What should we do instead ? Spring Boot provides something called @ConfigurationProperties that is there to separate and externalize configuration. Let me show how it works. If you are using Spring Boot. Spring Boot provides an elegant way to separate configuration and from the rest of your application: @ConfigurationProperties. By using Spring Boot’s @ConfigurationProperties you can easily encapsulate your configuration in a separate class and avoid scattering direct dependencies to your configuration files all over your code.

package com.gainjavaknowledge.springBootGenericResponseExample.config;

import jakarta.validation.constraints.NotNull;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.validation.annotation.Validated;

@Data
@Configuration
@ConfigurationProperties(prefix = "com.demo")
@Validated
public class LoadPropertiesConfig {

    @NotNull
    private String secretKey="default-secret-key";

    private String secretKey2="default";

    public String getKey(){return secretKey+secretKey2;}
}

//The cool thing now is that this configuration is just a 
//POJO (Plain Old Java Object) and we can inject it via the constructor
// to our service class.
@Service
public class EmployeeServiceImpl implements EmployeeService {

    private static final Logger LOGGER = LoggerFactory.getLogger(EmployeeServiceImpl.class);

    @Autowired
    private LoadPropertiesConfig properties;

    @Override
    public List<Employee> getAllEmployee() {
        LOGGER.info("Inside EmployeeServiceImpl getAllEmployee method.");
        LOGGER.info("Using config class : "+properties.getSecretKey());
        return null;
    }
}
com.demo.secret-key= my-secret-key
com.demo.db-url = localhost:config
com.demo.db-port = 8090

The service shouldn’t need to know where the configuration comes from. It shouldn’t have to deal with the underlaying source of the properties. It only need an instance of the properties class and it’s good to go.

Cool stuff you can do with configuration properties We can also combine property values. You might enter the database url and port separately in the properties file but in the config class you can create a getter that joins them together for the service.

Config properties also supports validation of properties via the spring-boot-starter-validation package.

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.validation.annotation.Validated;

@Data
@Configuration
@ConfigurationProperties(prefix = "com.demo")
@Validated
public class LoadPropertiesConfig {

    @NotNull
    private String secretKey="default-secret-key";

    private String secretKey2="default";

    public String getKey(){return secretKey+secretKey2;}
}

This will make sure that the configuration properties confirm to the required format before being loaded.

Conclusion :

@Value and @ConfigurationProperties annotation, both can be used to load external data mentioned in application.properties or application.yml file.

@Value is to inject a particular property value by its key into a variable (member field or constructor argument). We need to inject them one by one so it become long and messy. @Value approach is less flexible and have no built in support for validating the data.

@Value(“${com.demo.secret-key}”) will throw exception if there no matching key in application.properties/yml file. It strictly injects property value.

@ConfigurationProperties is used on a POJO bean to map properties to its fields or setters. Then you can use the bean to access the property values in your application logic.

@ConfigurationProperties(prefix = “com.demo”) injects POJO properties, it’s not strict, it ignores the property if there is no key in properties file.

This field doesn’t exists in properties file. It doesn’t throw error. It gets default value as null.

why is better to use ConfigurationProperties over Value: The main reason is that you could end with some text in the code forcing you to do full-text search to understand where a Value property is used.

Instead of using @Value annotation multiple time to read value from properties file . We can use @configurationProperties one time.

Spring Boot
Spring
Configurationproperties
Value
Gain Java Knowledge
Recommended from ReadMedium