Inject hardcoded Value
To inject simple hardcoded values, we can apply the @Value
annotation to the field or method/constructor parameter level of the Spring managed beans. The argument passed to the @Value annotation can only be a String. Spring will automatically convert the value to the specified type and assign the converted value.
@Component
public class Vehicle {
@Value("4")
private int wheelCount;
}
@Component
public class Vehicle {
private int wheelCount;
@Value("4")
public void setWheelCount(int wheelCount) {
this.wheelCount = wheelCount;
}
}
@Component
public class Vehicle {
private int wheelCount;
public Vehicle(@Value("4") int wheelCount) {
this.wheelCount = wheelCount;
}
}
All three versions will set 4 to field wheelCount
.
Inject Value from another class
Suppose you have created a class to hold constant values.
@Component
public class AppConstants {
public int wheelCount = 4;
}
We can use Spring Expression Language (SpEL) to inject this value to another bean field. We have to use #{<bean name>.<field name>}
to access the constant value. As we already know, if we don’t explicitly specify the bean name, class names will be used as the name. Only the first letter will be downcasted. So the name of AppConstants bean would be appConstants.
Now use SpEL in value annotation.
@Component
public class Vehicle {
@Value("#{appConstants.wheelCount}")
private int wheelCount;
}
It can also be used in the setter method or constructor parameter.
Inject Value from property file
To understand this first create a AppConstants.properties
file under the src/main/resources
folder with the following content.
vehicle.wheelCount=4
To load properties files into ApplicationContext, use the @PropertySource
annotation on @Configuration
class and specify the properties file path.
@PropertySource("classpath:AppConstants.properties")
@Configuration
public class AppConfig {
}
We can use Spring Expression Language (SpEL) to inject value from the property file to the bean field. We have to use ${<property key name>}
to access the value.
@Component
public class Vehicle {
@Value("${vehicle.wheelCount}")
private int wheelCount;
}
This is how we directly inject value into a field using @Value annotation. You can also access property value using a special bean called Environment
. Consider the Environment as an interface to easily access property values.
@Service
public class Vehicle {
@Autowired
private Environment env;
public int getWheelCount() {
return env.getProperty("vehicle.wheelCount", Integer.class);
}
}
This is as simple as the above example. Also please note, as we are expecting Integer value, we have specified the type as the second target. Otherwise it will return String.
Inject Collections
Now consider you need to access a collection of values rather than individual values. To achieve that, we can explicitly initialize and return a collection as a @Bean configuration and then inject the collection using @Autowired annotation.
@Configuration
public class AppConfig {
@Bean("availableGears")
public List<String> getAvailableGears() {
return Arrays.asList("1", "2", "3", "4", "5", "R");
}
}
@Component
public class Vehicle {
@Autowired
private Collection<String> availableGears;
private int wheelCount;
}
@Autowired and @Qualifier annotation
We already know that @Autowired annotation allows Spring to resolve and inject another bean into the bean where it is declared. By default, Spring resolves @Autowired entries by type.
Let’s assume we have the following beans.
public interface Engine {
void start();
}
@Component
public class TwoStrokeEngine implements Engine {
public void start() {
System.out.println("Starting two stroke engine...");
}
}
@Service
public class Vehicle {
@Autowired
private Engine engine;
public void start() {
engine.start();
}
}
You see, Vehicle depends on Engine implementation. As there is only a single implementation of Engine interface available, Spring will inject TwoStrokeEngine without any issue.
Now let’s add another implementation called FourStroke.
@Component
public class FourStrokeEngine implements Engine {
public void start() {
System.out.println("Starting four stroke engine...");
}
}
This time you will get following exception –
org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.kcs.api.Engine' available: expected single matching bean but found 2: fourStrokeEngine,twoStrokeEngine |
The reason is simple. When Spring tries to inject an implementation of Engine interface in Vehicle bean, as two implementations are available, Spring will get confused and throw this exception.
This is a common scenario. Now the question is how to solve this?
When there are multiple implementations of the same type, we can use the @Qualifier
annotation to avoid ambiguity. We have to pass the bean name to let Spring know which implementation to use. So the following code will work fine.
@Service
public class Vehicle {
@Autowired
@Qualifier("twoStrokeEngine")
private Engine engine;
public void start() {
engine.start();
}
}
If you don’t specify the @Qualifier annotation and there are multiple implementations, as a fallback match, the declared field name is considered as a default qualifier value. So, without @Qualifier annotation, above bean is will be treated as –
@Service
public class Vehicle {
@Autowired
@Qualifier("engine")
private Engine engine;
public void start() {
engine.start();
}
}
Of course this will not work as two available beans of type Engine are: twoStrokeEngine and fourStrokeEngine.
Now let’s change the field name from engine to twoStrokeEngine.
@Service
public class Vehicle {
@Autowired
private Engine twoStrokeEngine;
public void start() {
twoStrokeEngine.start();
}
}
This will work just fine as twoStrokeEngine is used as the qualifier value and a bean is available with this name.
Another option is, we can use @Primary annotation to give preference to a bean when multiple beans are qualified to autowire. There should be only one @Primary bean among the same type of beans.
@Component
@Primary
public class TwoStrokeEngine implements Engine {
public void start() {
System.out.println("Starting two stroke engine...");
}
}
In this case, if we don’t use @Qualifier annotation, TwoStrokeEngine will be injected.
That’s it for now. Hope you have enjoyed this tutorial. If you have any doubt, please ask in the comment section. I will try to answer that as soon as possible. Till then, bye bye.
Itís nearly impossible to find experienced people on this subject, but you sound like you know what youíre talking about! Thanks