You are here
Home > java >

Autowiring in Spring

Autowiring in SpringIf you are a Java developer, dependency Injection in Spring framework must not be the new term for you. One of the key features of Spring framework is dependency injection, which makes it easy to manage dependencies between objects. On the other hand, autowiring is a form of dependency injection in Spring that allows IOC container to automatically wire beans together without the need for explicit configuration. In this article, we’ll explore autowiring in Spring, the different ways of doing it, its features, limitations, and how to use it effectively with ample amount of examples covering all the scenarios.

Autowiring in Spring not only reduces boilerplate code but also simplifies maintenance and testing. However, while autowiring is a handy tool in our development process, it’s important to have a crystal clear understand of it to get the most out of it. In this article, we’ll explore the ins and outs of autowiring in Spring with examples and discuss some important tips in order to optimize our application’s performance.

What is Autowiring in Spring?

Autowiring is a mechanism in Spring that allows the framework to automatically detect and inject the dependent beans to the properties of the target bean without the need for explicit configuration. This can save a lot of time and effort, especially in large-scale applications where there are a large number of dependencies between objects. When we apply autowiring, Spring looks for the beans of the required dependency type in the container and automatically injects them into the dependent object.

Note: Since the autowiring is part of Spring Core Framework, all concepts will also be applicable in Spring Boot.

When to use @Autowired Annotation?

When we want to instruct the Spring container to detect and inject dependent beans to the properties of the target bean automatically, we use @Autowired annotation. In other words, when we want to enable autowiring on a specific property, we can achieve it by using the @Autowired annotation. This annotation can be used to inject a bean into another bean. When a bean is autowired, Spring will automatically resolve its dependencies and create the required objects.

Where can we use @Autowired Annotation?

We can use the @Autowired annotation at constructor level, field level, setter method level, and normal method level.

What are the limitations of Autowiring in Spring?

There are some limitations while we apply autowiring in Spring:

1) Autowiring in Spring is possible only on reference type/object type properties. In other words, we can’t apply it with other property types such as primitive types, String types etc.

2) Since autowiring is done automatically, it can create an ambiguity issue when there are two beans of the same type. However, this issue can be handled after applying some additional logic.

3)  It may lower the readability of the code.

What is the Ambiguity Issue while Using @Autowired?

If we have multiple possible dependencies to inject to a property of the target class and we didn’t specify which dependency needs to be injected, we might see NoUniqueBeanDefinitionException. For example, if we have a Person class and an Address class. Furthermore, Address class has two child classes: PermanentAddress and MailingAddress. Moreover, we autowired Address object in the Person class using @Autowired. In this case, Spring container will get confused which Address you want to autowire either Permenent or Mailing. As a result, we will see the NoUniqueBeanDefinitionException as shown below:

Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type  ‘………….’  available expected single matching bean but found 2: …, …

This is known as ambiguity issue.

In order to overcome from this issue, we explicitly need to specify a particular type of Address which needs to be injected.

Multiple Solutions of Ambiguity Issue

We have multiple approaches to resolve the ambiguity issue. Let’s go through them one by one.

1) Approach#1: Using @Primary annotation or ‘primary’ attribute

If you are using XML driven approach to declare spring beans, include ‘primary’ attribute on the targeted bean.

<bean id="pe" class="com.dev.entity.PermanentEmployee" primary="true"/>

<bean id="ce" class="com.dev.entity.ContractEmployee" />

If you are using only annotations, add class level @Primary annotation to the targeted bean as shown below. This is applicable in both the cases: either class is implementing another interface or extending another class.

@Primary
@Component
public class PermanentEmployee extends Employee {
       .....
}

@Component
public class ContractEmployee extends Employee {
       .....
}

2) Approach#2: Using @Qualifier annotation along with @Autowired

From the above example, if we want to autowire ContractEmployee using @Qualifier along with @Autowired, we can do it as shown below:

public class XYZCompany{

   @Autowired  
   @Qualifier("contractEmployee")
   private Employee employee;

}

Here, since we have not provided any id of ‘ContractEmployee’, Spring container will take the name of class as it is with first letter in lower case by default. Hence, id for ContractEmployee becomes ‘contractEmployee’.

If you are using XML driven approach to define beans, you should use the id of that bean inside @Qualifier annotation.

3) Approach#3: Bean ID Matching (By updating bean id of dependent class)

There is one more way to resolve the ambiguity issue. We can take the target class bean property name (on which @Autowired is applied) as the dependent spring bean class id. For example, below code demonstrates the concept:

public class XYZCompany{ 
   @Autowired 
   private Employee employee;
}

Let’s assume that we want to make ContractEmployee as dependent. Since target bean property name is ’employee’, we can do it by making ContractEmployee’s bean id also as ’employee’.

<bean id="employee" class="com.dev.entity.ContractEmployee" />

On doing so, the ambiguity issue will be resolved.

Note: If we apply all three approaches to resolve the ambiguity issue for the same target bean, the @Qualifier annotation approach will get the high priority and be effective. If we apply other two approaches except @Qualifier, the ‘primary’ approach will get the higher priority.

Below is the list of all possible combinations of approaches and the result:

Primary & Qualifier => Qualifier will take precedence

Qualifier & Bean Id Matching => Qualifier will take precedence

Primary & Bean Id Matching => Primary will take precedence

Primary & Qualifier & Bean Id Matching => Qualifier will take precedence

What are the different ways to implement Autowiring in Spring?

There are multiple ways to implement autowiring in Spring. Let’s discuss them one by one.

Autowiring through Constructor Injection

Autowiring through Constructor injection is a way of implementing autowiring where the dependencies are injected through the constructor. In this type of autowiring, IOC container looks for a constructor that matches the arguments of the bean being created and injects the dependencies accordingly.
Let’s take an example of autowiring repository class in a service class to demonstrate autowiring through constructor injection:

public class UserService {
   
   private UserRepository userRepository;

   @Autowired
   public UserService(UserRepository userRepository) {
      this.userRepository = userRepository;
   }
}

In the above example, the UserRepository is injected into the UserService through the constructor.

Implicit Single Constructor Injection (Since Spring 4.3)

Since Spring 4.3, if our class has a single constructor only, then its not mandatory to apply @Autowired. On the other hand, if the class has more than one constructor, you need to instruct Spring container which one you want to use with the help of @Autowired.

For example, if we consider the above example, it has only one constructor. In this case, we don’t need to apply @Autowire. It will be injected implicitly by the Spring container.

Autowiring through Setter Injection

Autowiring through setter injection is a way of implementing autowiring where the dependencies are injected through a setter method. In this type of autowiring, IOC container looks for a setter method that matches the type of the bean being created and injects the dependencies accordingly.
Here is an example of setter injection:

public class UserService {
   
   private UserRepository userRepository;

   @Autowired
   public void setUserRepository(UserRepository userRepository) {
      this.userRepository = userRepository;
   }
}

In the above example, the UserRepository is injected into UserService through the setter (setUserRepository) method.

Autowiring through Field Injection

Autowiring through field injection is a way of implementing autowiring where the dependencies are injected directly into the fields of the bean. In this type of autowiring, IOC container looks for a field that matches the type of the bean being created and injects the dependencies accordingly.
Let’s take an example of field injection:

public class UserService {

   @Autowired
   private UserRepository userRepository;

}

In the above example, the UserRepository is injected into UserService directly into the field.

Autowiring through an normal Method Injection

Autowiring through a normal method injection is a way of implementing autowiring where the dependencies are injected through a method. In this type of autowiring, IOC container looks for a method that matches the type of the bean being created and injects the dependencies accordingly. The notable point here is that the normal method must have the same signature as a setter method.
Here is an example of method injection:

public class UserService {
   
   private UserRepository userRepository;

   @Autowired
   public void setUserRepo(UserRepository userRepository) {
      this.userRepository = userRepository;
   }
}

In the above example, the UserRepository is injected into UserService through the setUserRepo method.

What are the different ways to declare Autowiring in Spring?

There are multiple ways to declare autowiring in Spring.

Using XML Configuration

XML configuration is one of the oldest and most traditional ways to declare autowiring in Spring. In XML configuration, the autowiring is declared using the <bean> element.
Let’s take an example of XML configuration for autowiring:

<bean id="userService" class="com.example.UserService">
   <property name="userRepository" ref="userRepository"/>
</bean>

<bean id="userRepository" class="com.example.UserRepository"/>

In the above example, the UserService bean is declared with a property called userRepository, which is set to the userRepository bean.

Using Annotation-Based Configuration

Annotation-based configuration is the modern way to declare autowiring in Spring. In annotation-based configuration, the autowiring is declared using annotations such as @Autowired, and @Qualifier.
Here is an example of annotation-based configuration for autowiring:

@Service
public class UserService {

   @Autowired
   private UserRepository userRepository;
}

@Repository
public class UserRepository {
      ......
}

In the above example, the UserService and UserRepository classes are annotated with @Service and @Repository, respectively, which tells Spring to treat them as beans and autowire them as required.

Using Java Configuration

Java configuration is another modern way to declare autowiring in Spring. In Java configuration, the autowiring is declared using pure Java code using annotation @Configuration in combination of @Bean.
Here is an example of Java configuration for autowiring:

@Configuration
public class AppConfig {
     
     @Bean
     public UserService userService() {
           return new UserService(userRepository());
     }

     @Bean
     public UserRepository userRepository() {
          return new UserRepository();
     }
}

@Service
public class UserService {

    @Autowired
    private UserRepository userRepository;

    public UserService(UserRepository userRepository) {
       this.userRepository = userRepository;
    }
}

@Repository
public class UserRepository {}

In the above example, the AppConfig class is annotated with @Configuration, which tells IOC container to scan the package for components to autowire. The AppConfig class also declares two beans, userService and userRepository, which are autowired using constructor injection in the UserService class.

What are the Best Practices and Considerations while using Autowiring?

Avoid Overuse of Autowiring

While autowiring can be a suitable way to manage dependencies between objects, it should not be overused. Overuse of autowiring can lead to code that is difficult to read and maintain, and can also create hidden dependencies that are hard to identify. Therefore, it is important to carefully consider which dependencies should be autowired and which should be explicitly declared.

Use Constructor Injection for Mandatory Dependencies

We should consider constructor injection is a preferred way of autowiring dependencies that are mandatory for the object to function properly. This is because constructor injection ensures that the object is in a valid state before it is used. In contrast, setter injection and field injection can leave the object in an invalid state if the dependencies are not properly set.

Use Qualifiers to Disambiguate Dependencies

In some cases, there may be multiple beans of the same type that need to be autowired. In this case, Spring may not be able to determine which bean to use for autowiring. To disambiguate these dependencies, you can use the @Qualifier annotation or other appropriate approached as aforementioned to specify which bean should be used.

Avoid Circular Dependencies

Circular dependencies occur when two or more objects depend on each other, either directly or indirectly. Circular dependencies can cause problems with object initialization and can make it difficult to reason about the code. It is generally best to avoid circular dependencies if possible, by using techniques such as interface-based programming or breaking the dependency cycle with a third object.

Use Mocking for Unit Testing

When writing unit tests for objects that use autowired dependencies, it is important to use mocking to isolate the object being tested from its dependencies. This allows you to test the object in isolation and avoid dependencies on external systems or resources. Mocking frameworks such as Mockito or EasyMock can be used to create mock objects for autowired dependencies.

FAQ

Can we apply @Qualifier annotation at the constructor level?

We can’t. If we have @Autowired annotation at the constructor level, we can use @Qualifier annotation at the parameter of the constructor  but not above the constructor. For example, below code demonstrates the correct use of @Qualifier at constructor level.

public class XYZCompany{ 
    
   private Employee employee;

   @Autowired 
   public XYZCompany(@Qualifier("contractEmployee") Employee employee){
      this.employee=employee;
   }
}

What is difference between autowiring using XML vs. @Autowired?

In XML driven configurations, we can do autowiring using setter methods and parameterized constructor, whereas Using @Autowired annotation we can do autowiring in field, setter method, parameterized constructor, and normal method. Here, the method signature of the normal method must be same as the setter method.

I am using XML driven approach to specify bean definitions. My @Autowired or @Required annotations are not working. How to resolve it?

The most probable reason could be that you have not included an additional tag in your configuration file (applicationContext.xml) which enables functioning of some annotations such as @Required, @Autowired, @PostConstruct, @PreDestroy, @Resource. You can enable these annotations by adding below tag in your applicationContext.xml.

<context:annotation-config/>

Which is better to use: Field level autowiring or Constructor level?

Many developers prefer to use autowiring at field level due to ease in coding. If we use field level autowiring, the IOC Container will use a lot of reflection API in order to access the private field and its annotation before performing the autowiring. In case of constructor level autowiring, the autowiring will be completed along with target class object creation. Therefore, in order to have a better performance, we should use constructor level autowiring.

Conclusion

Autowiring is a powerful feature of Spring that can simplify the management of dependencies between objects. In this article, we have covered the basics of autowiring, different ways of implementing autowiring in Spring, including constructor injection, setter injection, field injection, and method injection. We have also looked at the different ways in which autowiring can be declared in Spring, including XML configuration, annotation-based configuration, and Java configuration. Finally, we have discussed some best practices and considerations to keep in mind when using autowiring in Spring applications.

With this knowledge and by following these best practices, we can effectively use autowiring in our Spring based projects and write readable, cleaner, and maintainable code. We can build robust and scalable applications with the powerful features of Spring, including autowiring, that meet the needs of our users and business.

♥ If you want to learn more on similar concepts, kindly visit Spring Core Tutorials section.

 

Leave a Reply


Top