In this comprehensive guide, we will delve into the details of using @Value annotation in different scenarios.
Whether it’s injecting values from property files, environment variables, or system properties, this guide will equip you with the knowledge to harness the power of @Value annotation for resolving configuration values in your Spring applications.
By the end of this guide, you will have a solid understanding of how to use @Value annotation effectively in Spring applications.

Understanding @Value Annotation

The @Value annotation in Spring is a powerful tool for injecting values into Spring beans. It can be used to inject property values from various sources such as property files, system properties, environment variables, and command-line arguments.

With @Value, you can inject simple values like strings and numbers, as well as more complex objects such as arrays, lists, and maps into your Spring components.
This annotation provides a convenient way to externalize configuration and make your code more flexible and easier to maintain.

Basic Concept and Usage

With @Value, you can inject values directly into fields, constructor parameters, or setter methods of your Spring beans. For example, you can inject a simple string value as follows:

@Value("demo app")
private String name;

Working with System Properties and Environment Variables

Any property or environment variable can be used as a value for the @Value annotation by enclosing the name of property between ${}. For example:

@Value("${app.url}")
private String appURL;

Here, the property app.url might be defined inside properties file or application environment.

Leveraging SpEL (Spring Expression Language) with @Value

Spring Expression Language (SpEL) can be used with the @Value annotation to create more dynamic value assignments. For example:

@Value("#{systemProperties['user.language']}")
private String userLanguage;

In this example, user.language is a system property and its value will be injected into userLanguage field.

If there is no system property found, then null will be assigned.

Setting Default Values

We have seen that there are different ways to inject values in fields using @Value annotation such as from property file, system properties, environment etc.

But what if there is no property defined at the source location, the value will be null.

So, we can also define a default value using colon(:) in case the property could not be found. Example,

@Value("${admin.mail:default@example.com}")
private String adminEmail;

@Value("#{systemProperties['user.language'] ?: 'English'}")
private String userLanguage;

Constructor Injection

Constructor injection is a powerful feature in Spring that can be used along with the @Value annotation.
By annotating a constructor parameter with @Value, you can directly inject property values into your beans, making your components more self-contained and easier to test.

private final String customProperty;

public Example(@Value("${custom.property}") String customProperty) {
    this.customProperty = customProperty;
}

Value derived from environment-specific property sources can be directly injected into your bean during construction.

Setter Injection

Setter injection, when used with the @Value annotation, allows for more flexibility in injecting property values into your beans.
By using setter methods along with @Value, you can provide default values for properties or override them with the configured values.

private String customProperty;

@Value("${custom.property:default}")
public void setCustomProperty(String customProperty) {
    this.customProperty = customProperty;
}

Consider using setter injection when you need more dynamic control over property values at runtime.

Field Injection

Field injection with the @Value annotation allows you to inject property values directly into your fields.
While convenient, it’s important to use this approach judiciously as it can lead to tight coupling between your components and configuration values.

@Value("${custom.property}")
private String customProperty;

With field injection, be mindful of the impact on the readability and testability of your codebase.

Inject Map using @Value

You can also inject key-value pairs from a property into a field that is of type java.util.Map.

For this, define a map in application.properties file as below

key.values={'KEY1': 'value1', 'KEY2': 'value3', 'KEY3': 'value5'}

Then, define a property whose type is Map and annotate it with @Value as shown below

@Value("#{${key.values}}")
Map<String, String> propertyMap;

and it will be automatically populated with key-value pairs.

You can also assign a value for particular key directly into a property. Example,

@Value("#{${key.values}.KEY1}")
String keyOneVal;

If you are not sure about a key being present in the map, then instead of using dot, enclose the key name inside square brackets.

@Value("#{${key.values}['KEY1']}")
String keyOneVal;

If there is no mapping for this key in the map, then the property will be set to null.

Pros and Cons of Using @Value

While @Value annotation provides a convenient way to inject values into Spring beans, it comes with its own set of advantages and limitations.

ProsCons
Allows injection of externalized propertiesCan lead to tight coupling with property keys
Provides flexibility in changing property values without recompiling the codeCan make testing more complex due to reliance on external configurations
Useful for quick prototyping and developmentMay lead to runtime errors if key is mistyped or property is missing

Conclusion

@Value annotation in Spring provides a powerful mechanism for injecting values from properties files, environment variables, or any other Spring managed beans into your Spring components.
It offers flexibility and ease of use, allowing you to easily inject values into fields, constructor arguments, or setter methods.
By leveraging @Value annotation, you can effectively externalize configuration properties and dynamically configure your Spring components, making your application more adaptable and easier to maintain.