Spring autowired feature enables injection of the object dependency implicitly. In this article, we will cover different features and techniques for the bean autowiring provided by Spring Framework.
Introduction
Spring Framework (2.5) introduced the @Autowired annotation for Dependency Injection. In this article, we will learn how to enable Spring bean autowiring feature and the different techniques to inject bean dependencies in our code base.
1. Enabling @Autowired Annotations
To enable Spring based injection, we need to pass certain information to the underlying Spring IoC container to detect all components. This can be achieved with the help of AnnotationConfigApplicationContext and @ComponentScan annotation. For Java based configuration
@Configuration
@ComponentScan("com.java.web")
public class WebConfig {
// ...
}
The XML configuration equivalent
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="org.example.web"/>
<!-- ... -->
</beans>
2. Using @Autowired Annotations
Spring Framework provided the following type of bean autowiring.
- Setter-based autowiring.
- Constructor based bean wiring.
- Field or property based autowiring.
2.1 @Autowired by Setter
Setter method based annotation allow @Autowired annotation on the setter method. Spring IoC container will call the setter method when the give instance created by Spring.
public class CustomerService {
private ModelMapper modelMapper;
@Autowired
public void setModelMapper(ModelMapper modelMapper) {
this.modelMapper = modelMapper;
}
}
2.2 @Autowired by Constructor
public class CustomerService {
private ModelMapper modelMapper;
@Autowired
public CustomerService(ModelMapper modelMapper) {
this.modelMapper = modelMapper;
}
}
2.3 @Autowired by Properties
The annotation used directly on properties, eliminating the need for getter and setters.
public class CustomerService {
@Autowired
private ModelMapper modelMapper;
}
3. @Autowired as Optional
The @Autowired
dependency is required by default. This means before injecting the dependency, the dependency being injected should be available.
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {
boolean required() default true;
}
Spring throw NoSuchBeanDefinitionException
exception if the required dependency is not available with the container. We can change this behavior by passing false for the required flag.
@Autowired(required =false )
private ModelMapper modelMapper;
4. The Qualifier Annotation.
By default, the @Autowired resolve dependencies by type. This works fine until we have only one bean with the same type. Spring framework will throw an exception if more than one bean with the same type is available with the container. The @Autowired annotation will not work in this case, @Qualifier annotation is used for these use case. Let’s take this example
@Service("userServiceImpl")
public class UserServiceImpl implements UserService {
@Override
public void enableUser() { }
}
@Service("defaultUserService")
public class DefaultUserService implements UserService {
@Override
public void enableUser() {}
}
public class OrderFacade {
@Autowired
private UserService userService;
}
If we run this code, we may see the following exception on application startup
Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'orderController': Unsatisfied dependency expressed through field 'orderFacade'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'orderFacade': Unsatisfied dependency expressed through field 'userService'; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException:
No qualifying bean of type 'com.javadevjournal.rest.service.UserService' available: expected single matching bean but found 2: defaultUserService,userServiceImpl
4.1. Autowiring by @Qualifier
The @Qualifier
annotation should be used to show Spring about the type of bean injection requested.
public class OrderFacade {
@Qualifier("userServiceImpl")
@Autowired
private UserService userService;
}
The @Qualifier annotation works by matching the name defined with @Service annotation.
4.2. Autowired by Name
Spring framework uses bean name as the default qualifier value. Let’s change the code to understand it more clearly.
@Service("userService")
public class UserServiceImpl implements UserService {
@Override
public void enableUser() { }
}
@Service("defaultUserService")
public class DefaultUserService implements UserService {
@Override
public void enableUser() {}
}
public class OrderFacade {
@Autowired
private UserService userService;
}
Spring framework will inject bean of type UserServiceImpl as bean name matches with the definition.
Summary
In this article, we discussed Spring autowired and bean autowiring. We covered different bean injection techniques using@Autowired annotation. In the last section, we discussed why to use @Qualifier annotation in your application.
Comments are closed.