Here’s an interesting post on compact equals and objects-powered hashCode(), if you haven’t already been using them. Worth a read.
In my previous post I briefly introduced the concept of Spring’s
@Autowired annotation. This post goes more in-depth about this annotation, and its importance when developing with the Spring framework.
Spring uses the
@Autowired annotation when it determines where it needs to inject a given
@Bean. You can see this in the example below:
This example uses
@Autowired on a private member variable referenced via class. In this example, the
@Component is on the
WeatherService class. The
DependencyInjectionWithSpring class references the
WeatherService class directly. I’ve annotated this reference with the
@Autowired annotation. Spring then knows that it needs to find a bean (component) that matches. In this case, it finds the
WeatherService class and injects it into the
You can also reference with
@Autowired via interface:
Here, I change the
WeatherService class to be named WeatherServiceImpl, and have it implement the
WeatherService interface, which I’ve also defined.
DependencyInjectionWithSpring now references this interface (
WeatherService), and the
@Autowired annotation stays. Spring then knows that it needs to find a bean/component that implements the
WeatherService interface. It finds the
WeatherServiceImpl class and injects it into the
DependencyInjectionWithSpring as a dependency (
Field X in Y required a single bean, but 2 were found
What happens if we have multiple beans (components) that implement the same interface? Like this:
CloudyWeatherServiceImpl implement the
WeatherService interface. The
DependencyInjectionWithSpring class depends on an implementation of
WeatherService. Both of these classes would work, since they implement that interface. Spring is aware and manages both of these classes, since they are annotated with the
@Component annotation. How does Spring know which one to choose? Let’s run the application and see what happens:
The application is unable to start. Spring can’t determine which bean to set for the
How do I fix this?
To resolve this issue and tell Spring which bean to use in this situation, we have a few options.
The first option is to follow the first suggestion given in the exception:
Consider marking one of the beans as @Primary…
@Primary annotation can be used to indicate to Spring which bean to use. In this case, I add the
@Primary annotation to the SunnyWeatherServiceImpl:
Now when I run the application, it starts up with no errors and runs as expected, injecting the SunnyWeatherServiceImpl (the one with the
@Primary annotation) into the
There’s another option that Spring gives us, as mentioned in the error message from above:
or using @Qualifier to identify the bean that should be consumed
@Qualifier is a Spring annotation that allows us to tell Spring which bean we want to inject. See below:
Pay particular attention to the
DependencyInjectionWithSpring class. The
weatherService dependency in this class is now annotated with
@Qualifier(value="cloudyWeatherServiceImpl"). This tells Spring to use the
cloudyWeatherServiceImpl bean when injecting this dependency.
Now when I run the application, again it starts up with no errors and runs as expected. This time, I told Spring to use the
cloudyWeatherServiceImpl class and it prints out
The weather is cloudy with a 90% chance of rain as expected.
There’s yet another way to indicate to Spring which bean to inject. This is by naming the variable of the dependency the name of the class we want to inject. Like so:
WeatherService interface gets the name
cloudyWeatherServiceImpl. This tells Spring that I want to inject the bean with the name
cloudyWeatherServiceImpl. When I run this code, the application again starts up with no problems, and I again get the expected output.
@Autowired annotation is used to indicate where to inject a Spring-managed bean. The
@Primary annotation allows us to indicate which bean to use when multiple beans that match are present. The
@Qualifier annotation allows us to specify a specific bean to inject on a given dependency. Finally, we learned that we can name the dependency with the bean name to also specify which bean to inject.