Spring Framework - Dependency Injection
Tags: spring, opensource
Published: 2020-02-27 07:04:44

The Spring Framework empowers developers to create Java applications and deliver on business focus quickly. The primary benefit of Spring is its inversion-of-control container approach to dependency injection, removing the need for hard-coded wiring as the framework can inject dependencies where they are needed. 

# Benefits
• Testability
• Maintainability
• Scalability

## Testability
Because Spring decouples object contracts from their implementations and autowires them using Spring's Application Context, we can create units of work that are much easier to write tests for. 

## Maintainability
By using Spring's opinionated architecture, developers can quickly identify and familiarize themselves with an application's business focus. Most frameworks are popular because they operate on some fundamentals that are easy to grasp, which is one of Spring's strengths.

## Scalability
Spring containers utilizing Spring Boot are able to deploy as standalone JARs and run on an included Tomcat server. Between Spring's `@Profile` annotations and the Spring Application Context Configuration, there is a lot of flexibility to control the behavior of a Spring application in varying environments. 

# IoC/Dependency Injection in Spring
Understanding dependency injection is a fundamental component of understanding the Spring Framework. [Spring Boot](https://spring.io/projects/spring-boot) is the most popular project developers get started with and is an excellent sandbox for development ideas around dependency injection. Let's take a look, getting started with how we can store configurations in a Java class and tell Spring how to use it with the `@Configuration` annotation.

## ApplicationContextConfiguration
Using the `@Configuration` annotation enables Java configuration of specific dependencies. In the example below, we will tell Spring what implements the` UserDao` and what `DataSource` to build. We are assuming the `UserDao` uses constructor injection to determine its database connection dependency.
```java
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MyApplicationContextConfiguration {  // (1)
     @Bean
    public DataSource dataSource() {  // (2)
        MysqlDataSource dataSource = new MysqlDataSource();
        dataSource.setUser("root");
        dataSource.setPassword("s3cr3t");
        dataSource.setURL("jdbc:mysql://localhost:3306/myDatabase");
        return dataSource;
    }
     @Bean
    public UserDao userDao() { // (3)
        return new UserDao(dataSource());
    }
}
```
1. The class name used with a `@Configuration` annotation will be used in configuring the `ApplicationContext` in Spring
2. A `DataSource` with the Spring `@Bean` is created 
3. A `UserDao` Spring `@Bean` is created, calling the `dataSource()` method on the `DataSource @Bean`

# ApplicationContext
Spring uses the `ApplicationContext` to determine what `@Bean`s to instantiate and inject into dependencies. 
```java
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import javax.sql.DataSource;
public class MyApplication {
     public static void main(String[] args) {
    // (1)
        ApplicationContext ctx = new AnnotationConfigApplicationContext(MyApplicationContextConfiguration.class);
         UserDao userDao = ctx.getBean(UserDao.class); // (2)
        User user1 = userDao.findById(1);
        User user2 = userDao.findById(2);
         DataSource dataSource = ctx.getBean(DataSource.class); // (3)
        // etc ...
    }
}
```
1. Construct an `ApplicationContext` by passing in `MyApplicationContextConfiguration` class, which will create a `UserDao` and a `DataSource`
2. Get the fully configured `UserDao`, including its dependency on a `DataSource` for JDBC connection
3. We can also get the exact same instance of the `DataSource` used in `UserDao` from the `ApplicationContext`

## Using @ComponentScan to inject @Components
We don't need to tell Spring to look at our Application Context Configuration to figure out what `@Bean`s exist in our application. Instead, we can tell Spring where it can look for other `@Component`s in our application using the `@ComponentScan` annotation on our main `Application` class.
```java
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan  // (1)
public class MyApplicationContextConfiguration {
     @Bean
    public DataSource dataSource() {
        MysqlDataSource dataSource = new MysqlDataSource();
        dataSource.setUser("root");
        dataSource.setPassword("s3cr3t");
        dataSource.setURL("jdbc:mysql://localhost:3306/myDatabase");
        return dataSource;
    }
     // (2)
     // no more UserDao @Bean method!
}
```
1. Without any arguments, Spring will look for @Components in all Java classes in the same package
2. Why don't we need the UserDao @Bean in the Application Context Configuration anymore?
```java
import javax.sql.DataSource;
import org.springframework.stereotype.Component;
@Component // (1)
public class UserDao {
     private DataSource dataSource;
     private UserDao(DataSource dataSource) { // (2)
        this.dataSource = dataSource;
    }
}
```
1. Spring now knows the `UserDao` is a dependency it should manage and inject where needed
2. How does Spring know what to provide to the `UserDao` for its DataSource dependency?

While not required in the latest versions of Spring (4.2 and later), the `@Autowired` annotation can be used to explicitly mark the constructor injection method as dependent on the `DataSource @Bean` Spring will create.
```java
import javax.sql.DataSource;
import org.springframework.stereotype.Component;
import org.springframework.beans.factory.annotation.Autowired;
@Component
public class UserDao {
     private DataSource dataSource;
     private UserDao(@Autowired DataSource dataSource) {
        this.dataSource = dataSource;
    }
}
```
Injection Methods
• Constructor
• Setter
• Field

### Sources
Code examples used in this blog were adapted from [Marco Behler's _What is Spring Framework?_](https://www.marcobehler.com/guides/spring-framework#_introduction)