AdBlock Detected

It looks like you're using an ad-blocker!

Our team work realy hard to produce quality content on this website and we noticed you have ad-blocking enabled. Advertisements and advertising enable us to continue working and provide high-quality content.

Dependency injection in Spring

In this article, we will explain how does dependency injection work in Spring?. We will also see how we can use it in Spring applications.

What is Inversion of Control (IoC)?

The software principle of Inversion of Control transfers the control of our objects to a container or framework. We typically delegate the program flow to the framework, which has several advantages, including:

  1. Decoupling of code.
  2. Easier testing as isolated parts can be tested.
  3. Improved modularity.

To achieve Inversion of Control we can implement different software patterns, such as:

  • Strategy Pattern
  • Factory Pattern
  • Service Locator Pattern
  • Dependency Injection (DI)

Dependency Injection (DI)

Dependency Injection is a software pattern that implements Inversion of Control to resolve dependencies. In DI, objects define their dependencies with other objects. These dependencies are managed by a container, which is responsible for injecting them and creating the necessary beans through a process called Inversion of Control (IoC).

We can define and summarize this concept as the process of supplying an external dependency to a software component.

Benefits of Dependency Injection (DI)

Developers use dependency injection to achieve loose coupling and enhance the modularity and testability of software systems. Here are some reasons why dependency injection is beneficial:

  • Decoupling: Dependency injection decouples the dependencies between classes by enabling the provision of dependencies from external sources instead of creating or managing them within the class itself. This reduces the tight coupling between classes and promotes modular and independent components.
  • Flexibility: Dependency injection makes it easier to modify or replace dependencies without modifying the class that depends on them. By injecting dependencies from external sources, you can easily switch implementations or configurations, making the system more flexible and adaptable to changing requirements.
  • Testability: With dependency injection, it becomes easier to write unit tests for individual components. By injecting mock or stub dependencies during testing, you can isolate the component being tested and ensure that it functions correctly without relying on the behavior of the actual dependencies.
  • Reusability: By separating dependencies from the classes that use them, dependencies can be reused across multiple components. This promotes code reuse and eliminates the need to duplicate dependencies or tightly couple them to specific classes.
  • Modular Development: Dependency injection encourages modular development by promoting the separation of concerns. Developers can develop and test components independently, wiring their dependencies together later, which leads to improved code organization and maintainability.

Overall, dependency injection promotes better software design principles such as encapsulation, separation of concerns, and single responsibility, leading to more maintainable, flexible, and testable codebases.

The IoC Container in Spring

In Spring, the IoC container is represented by the ApplicationContext interface, which is responsible for configuring and instantiating all objects (beans) and managing their lifecycle.

We can create Dependency Injection in Spring through fields, setters, or constructors.

Constructor-Based Dependency Injection

In constructor-based Dependency Injection, the container invokes a constructor with arguments, where each argument represents a dependency.

Let’s see the configuration of a bean and its dependencies using Spring annotations:

@Configuration
Public class AppConfig {

@Bean
public Book book() {
  return new Book();
}

The first annotation we see, @Configuration, is necessary because it tells us that it is a bean definition class.

The next annotation we see, @Bean, indicates that we are going to define a bean. By default, Spring creates the bean with Singleton scope.

In Spring, we can also create beans using XML configuration, although it is not very common.

<bean id="book" class="org.refactorizando.library.BookImpl" /> 
<bean id="library" class="org.refactorizando.library.Library"> <constructor-arg type="BookImpl" index="0" name="book" ref="book" /> </bean>

Setter-based Dependency Injection

Setter-based Dependency Injection is similar to constructor-based Dependency Injection, with the only difference being that, once the object is created, its attributes are set using setter methods.

Let’s see an example using annotations:

@Configuration
Public class AppConfig {
@Bean
 public Library library() {
   Library library =  new Library();
   library.setBook(book());
   return library;

 }

Just like in the previous case, Dependency Injection can also be done through XML configuration:

<bean id="library" class="org.refactorizando.library.Library">
  <property name="book" ref="book"/>
</bean>

Spring generally recommends using constructor injection for mandatory dependencies and setter-based injection for optional dependencies.

Field-based Dependency Injection

In the case of field-based Dependency Injection (DI), we can achieve it by adding the @Autowired annotation to the field of the class for which we want its dependency:

public class Library {

@Autowired
private Book book;

}

In this case, we can use reflection to inject the “book” into the “library”.

Undoubtedly, this is a simple, practical, and clean system, but it should not always be used.

Performing dependency injection using reflection is more costly than using constructor or setter injection.

It is possible to violate the Single Responsibility Principle because it is easy to add dependencies, and if we make the mistake of adding too many, the class may appear to be performing more functions than it should.

Autowiring dependencies

Using autowiring allows us to automatically resolve dependencies between collaborating beans by inspecting the defined beans.

There are four different autowiring modes for a bean:

  • no: By default, Spring does not perform autowiring, and you need to explicitly specify the dependency name.
  • byName: Spring performs autowiring based on the property name. In other words, it searches for a bean with the same name as the property being set.
  • byType: Similar to the previous mode, but based on the property type. The only difference is that Spring searches for a bean with the same type as the property.
  • constructor: Spring performs autowiring by constructor, and it searches for beans with the same type as the constructor arguments..

Conclusion

In this article about How does dependency injection work in Spring?, we have explained in broad terms how Dependency Injection (DI) works and how to apply it. To delve further into concepts and knowledge about this design pattern, you may visit this article by Martin Fowler: https://martinfowler.com/bliki/InversionOfControl.html.

Leave a Reply

Your email address will not be published. Required fields are marked *