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 = 8090The 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.





