DEV Community

Michael Lamb
Michael Lamb

Posted on

Spring Framework - Dependency Injection

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 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 theUserDao and what DataSource to build. We are assuming the UserDao uses constructor injection to determine its database connection dependency.

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 @Beans to instantiate and inject into dependencies.

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 @Beans exist in our application. Instead, we can tell Spring where it can look for other @Components in our application using the @ComponentScan annotation on our main Application class.

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?
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.

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?

Top comments (0)