What is Inversion of Control (IoC) in Spring
Tags: java, tutorial, webdev, beginners
Published: 2022-02-22 13:49:22

## Meet Mr. Beans 🥸
A Bean is a **Java object.** That's it.
Java objects are units that hold data and logic which make our application do its work. Objects can depend on other objects (dependencies) to complete a certain task.

In Java, creating dependencies is usually done in the constructor of the class using the `new` keyword.

---

### Example of Traditional Bean Creation 🧑‍🔧
Say we have a `DownloadService` that depends on a `ConnectionService`.
The `ConnectionService` needs an **address** and a **password** to set up its connection.

```java
public class ConnectionService {  
      
    public ConnectionService(String address, String password)  
    {  
        // use address and password to set up the connection  
  }  
    public void connect()  
    {  
        // connecting things  
  }  
}
```
Now, if the `DownloadService` wanted to use the `ConnectionService` it has to know how to construct it. It has to get the password, the address and call the `ConnectionService` constructor.

```java
public class DownloadService {  
    ConnectionService connectionService;  
  
    public DownloadService()  
    {  
        String password = getPassword();  
        String address = getAddress();  
        connectionService = new ConnectionService(address, password);  
    }  
    public void download()  
    {  
        connectionService.connect();  
        // download things  
  }  
    private String getAddress()  
    {  
        return "address";  
    }  
  
    private String getPassword()  
    {  
        return "pass";  
    }  
}
```

This is all fine and dandy, but what if we had 10 or more classes that use the `ConnnectionService`? Then they all have to know how to get the password, the address and call the constructor. 

This is certainly not maintainable and hard to follow around.

## Inversion of Control (IoC) to the Rescue 🏋️‍♂️
In the software development world, there is a well-known rule called the Single Responsibility Principle. It urges developers to assign a single responsibility to a method or a class.
So in our above example, the `DownloadService` should not know how to construct the complicated `ConnectionService`, it should just use it.

What the **IoC pattern** suggests is that the `DownloadService` service should invert the responsibility of creating the `ConnectionService` to some other entity. 

This entity could be, for example, a **factory class**.

```java
public class ConnectionFactory {  
      
    public ConnectionService createConnectionService()  
    {  
        String password = getPassword();  
        String address = getAddress();  
        return new ConnectionService(address, password);  
    }  
  
    private String getAddress()  
    {  
        return "address";  
    }  
  
    private String getPassword()  
    {  
        return "pass";  
    }  
}
```
Then in the `DownloadService`, we call the `ConnectionFactoy` which knows how to construct a `ConnectionService` object.
```java
public class DownloadService {  
    ConnectionService connectionService;  
  
    public DownloadService()  
    {  
        connectionService = new ConnectionFactory().createConnectionService();  
    }  
    public void download()  
    {  
        connectionService.connect();  
        // download things  
  }  
}
```

## IoC in Spring ☘️
Spring offers a helping hand using the **[IoC Spring Container](https://docs.spring.io/spring-framework/docs/3.2.x/spring-framework-reference/html/beans.html)**. All we have to do is describe our beans to the container in a configuration class and it will give them to us whenever we want.

Let's test this with our above code:
```java
public class ConnectionService {  
  
    public ConnectionService(String address, String password)  
    {  
        // use address and password to setup the connection  
  }  
    public void connect()  
    {  
        System.out.println("Connecting...");  
        // connecting things  
  }  
}
```
Now, let's introduce the configuration class which will provide us with the `ConnectionService` bean.
```java
@Configuration
public class AppConfiguration {  
  @Bean  
  ConnectionService connectionService()  
    {  
        String address = getAddress();  
        String password = getPassword();  
        return new ConnectionService(address, password);  
    }  
  
    private String getAddress()  
    {  
        return "address";  
    }  
  
    private String getPassword()  
    {  
        return "pass";  
    }  
}
```
Two new things to note here:
- The `@Configuration` annotation indicates that the class has `@Bean` definition methods. So Spring container can process the class and generate Spring Beans to be used in the application.
- The `@Bean` declares the object returned from the method as a Bean to be managed by Spring IoC container.


Finally, let's check out our `DownloadService` class which will have the `ConnectionService` Bean injected in.
```java
@Component  
public class DownloadService {  
    private final ConnectionService connectionService;  
	
	@Autowired
    public DownloadService(ConnectionService connectionService)  
    {  
        this.connectionService = connectionService;  
    }  
    public void download()  
    {  
        connectionService.connect();  
        // download things  
  }  
}
```
An important detail to pay attention to here is the `@Component` and `@Autowired` annotations. 

The `@Component` will tell Spring to manage the `DownloadService` as a Bean. Doing this, Spring will create the class and inject any Beans it depends on (`ConnectionService` in this example) into the class.

The `@Autowired` will tell Spring to get the objects declared in the constructor parameters from the Spring IoC container, which in our case was declared in the `AppConfiguration` class.

---
Now, that was a good move to have the IoC principle implemented in our system. Spring, however, offers an even more convenient way to handle IoC.

We can remove the  `AppConfiguration` class and simply have the logic of instantiating the `ConnectionService` inside of it and have Spring create the Bean and make it ready for use.

```java
@Component  
public class ConnectionService {  
  
    public ConnectionService()  
    {  
        // use address and password to setup the connection  
        String address = getAddress();  
        String password = getPassword();  
    }  
    public void connect()  
    {  
        // connecting things  
    }  
      
    private String getAddress()  
    {  
        return "address";  
    }  
  
    private String getPassword()  
    {  
        return "pass";  
    }  
}
```
Note the `@Component` annotation which tells Spring to treat this class as a Bean and have it in the Spring IoC ready for the `DownloadService` to use.


## Beans' Life Cycle 🌕 🌖 🌗 🌘 🌑
Spring Bean factory manages the lifecycle of beans created through the Spring container and controls the creation and destruction of the beans.

Let's explore the phases of a Spring Bean's life cycle:

1. Bean definition. 
	- It's defined by the `@Bean` annotation over methods in the configuration file (the one annotated with `@Configuration` file). 
	- Or using the `@Component` annotation and its derivatives (`@Service`, `@Controller`, etc..) over classes.

2. Bean Instantiation.
	- Spring instantiate bean objects and loads the objects into the ApplicationContext.

3. Populating Bean properties.
	- Spring scans the beans and sets relevant properties as id, scope, and the default values.

4. Pre-Initialization
	- Spring’s [BeanPostProcessors](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/beans/factory/config/BeanPostProcessor.html) do their work.
5. AfterPropertiesSet
	- Spring executes the `afterPropertiesSet()` methods of the beans which implement InitializingBean.
6. Custom Initialization
	- Spring triggers any initialization methods that we define. 
7. Post-initialization
	- Spring’s [BeanPostProcessors](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/beans/factory/config/BeanPostProcessor.html) do their work for one more time.
8. Ready
	- The Bean is ready and injected into all other dependencies.
9. Pre-Destroy
	- Spring triggers `@PreDestroy` annotated methods in this phase 
10. Destroy
	- Spring executes the destroy() methods of DisposableBean implementations
11. Custom Destruction
	- Spring triggers any custom destruction methods that we've defined.

## Conclusion ✍️
The principle of Inversion of Control helps us write clean, maintainable code.

This can be achieved by separating the logic of creating complex objects into a class of their own (separation of concerns).

Spring offers a neat solution using Spring's `ApplicationContext` and Spring's IoC container. The container treats our objects as Beans which have life cycles managed by Spring and custom methods that we can introduce.