Nishajha
5 min readMar 15, 2021

--

Inversion of Control(IoC) & Dependency Injection

Inversion of Control

In traditional programming, the flow of the business logic is determined by objects that are statically assigned to one another. With Inversion of Control, the flow depends on the object graph that is instantiated by the assembler and is made possible by object interactions being defined through abstractions. The binding process is achieved through dependency injection, although some argue that the use of a service locator also provides inversion of control.

Inversion of control as a design guideline serves the following purposes:

  1. There is a decoupling of the execution of a certain task from implementation.
  2. Every module can focus on what it is designed for.
  3. Modules make no assumptions about what other systems do but rely on their contracts.
  4. Replacing modules has no side effect on other modules.

Ways to implement IoC

In object-oriented programming, there are several basic techniques to implement inversion of control. These are:

  1. using a factory pattern
  2. using a service locator pattern
  3. using a dependency injection of any given below type:
  • a constructor injection
  • a setter injection
  • an interface injection

The org.springframework.beansand org.springframework.context packages provide the basis for the Spring Framework’s IoC container. The BeanFactorythe interface provides an advanced configuration mechanism capable of managing objects of any nature. The ApplicationContextthe interface builds on top of the Bean Factory(it is a sub-interface) and adds other functionality such as easier integration with Spring’s AOP features, message resource handling (for use in internationalization), event propagation, and application-layer specific contexts such as the WebApplicationContext for use in web applications.

The Bean Factory is the actual representation of the Spring IoC container that is responsible for containing and otherwise managing the aforementioned beans. The Bean Factory interface is the central IoC container interface in Spring.

Dependency Injection

Dependency injection is a pattern we can use to implement IoC, where the control is inverted is setting an object’s dependencies.

Connecting objects with other objects, or “injecting” objects into other objects, is done by an assembler rather than by the objects themselves.

1.Constructor-Based Dependency Injection

In the case of constructor-based injection, the container will invoke a constructor with arguments each representing a dependency we want to set.

Spring resolves each argument primarily by type, followed by name of the attribute, and index for disambiguation. Let’s see the configuration of a bean and its dependencies using annotations:

@Configuration
public class AppConfig {
@Bean
public Item item1() {
return new ItemImpl1();
}
@Bean
public Store store() {
return new Store(item1());
}
}

The @Configuration annotation indicates that the class is a source of bean definitions. We can also add it to multiple configuration classes.

We use the @Bean annotation on a method to define a bean. If we don’t specify a custom name, then the bean name will default to the method name.

For a bean with the default singleton scope, Spring first checks if a cached instance of the bean already exists, and only creates a new one if it doesn’t. If we’re using the prototype scope, the container returns a new bean instance for each method call.

Another way to create the configuration of the beans is through XML configuration:

<bean id="item1" class="org.baeldung.store.ItemImpl1" /> 
<bean id="store" class="org.baeldung.store.Store">
<constructor-arg type="ItemImpl1" index="0" name="item" ref="item1" />
</bean>

2. Setter-Based Dependency Injection

For setter-based DI, the container will call setter methods of our class after invoking a no-argument constructor or no-argument static factory method to instantiate the bean. Let’s create this configuration using annotations:

@Bean
public Store store() {
Store store = new Store();
store.setItem(item1());
return store;
}

We can also use XML for the same configuration of beans:

<bean id="store" class="org.baeldung.store.Store">
<property name="item" ref="item1" />
</bean>

We can combine constructor-based and setter-based types of injection for the same bean. The Spring documentation recommends using constructor-based injection for mandatory dependencies, and setter-based injection for optional ones.

3. Field-Based Dependency Injection

In the case of Field-Based DI, we can inject the dependencies by marking them with an @Autowired annotation:

public class Store {
@Autowired
private Item item;
}

While constructing the Store object, if there’s no constructor or setter method to inject the Item bean, the container will use reflection to inject Item into Store.

We can also achieve this using XML Configuration.

This approach might look simpler and cleaner, but we don’t recommend using it because it has a few drawbacks such as:

  • This method uses reflection to inject the dependencies, which is costlier than constructor-based or setter-based injection.
  • It’s really easy to keep adding multiple dependencies using this approach. If we were using constructor injection, having multiple arguments would make us think that the class does more than one thing, which can violate the Single Responsibility Principle.

8. Autowiring Dependencies

Wiring allows the Spring container to automatically resolve dependencies between collaborating beans by inspecting the beans that have been defined.

There are four modes of autowiring a bean using an XML configuration:

  • no: the default value — this means no autowiring is used for the bean and we have to explicitly name the dependencies.
  • byName: autowiring is done based on the name of the property, therefore Spring will look for a bean with the same name as the property that needs to be set.
  • byType: similar to the byName autowiring, only based on the type of the property. This means Spring will look for a bean with the same type of property to set. If there’s more than one bean of that type, the framework throws an exception.
  • constructor: autowiring is done based on constructor arguments, meaning Spring will look for beans with the same type as the constructor arguments.

For example, let’s autowire the item1 bean defined above by type into the store bean:

@Bean(autowire = Autowire.BY_TYPE)
public class Store {

private Item item;
public setItem(Item item){
this.item = item;
}
}

We can also inject beans using the @Autowired annotation for autowiring by type:

public class Store {

@Autowired
private Item item;
}

If there’s more than one bean of the same type, we can use the @Qualifier annotation to reference a bean by name:

public class Store {

@Autowired
@Qualifier("item1")
private Item item;
}

--

--