Spring Boot Tutorial

Spring Boot - Software Setup and Configuration (STS/Eclipse/IntelliJ)

Prerequisite (Spring Core Concepts)

Spring Boot Core

Spring Boot with REST API

Spring Boot with Database and Data JPA

Spring Boot with Kafka

Spring Boot with AOP

Spring Dependency Injection with Example

Spring Dependency Injection (DI) is a core concept that allows an object to be provided its dependencies from the outside rather than the object creating them itself. This promotes the principle of Inversion of Control (IoC) and makes the application easier to test and more modular.

In this example, we'll demonstrate the Spring Dependency Injection using both XML-based and annotation-based configurations.

1. Maven Dependencies

First, set up a simple Maven project and include the following dependencies in your pom.xml:

<dependencies>
    <!-- Spring core -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>5.x.x.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.x.x.RELEASE</version>
    </dependency>
</dependencies>

2. Define the Beans

Let's have two simple classes:

public class Engine {
    public void start() {
        System.out.println("Engine started.");
    }
}

public class Car {
    private Engine engine;

    // Setter for DI
    public void setEngine(Engine engine) {
        this.engine = engine;
    }

    public void drive() {
        engine.start();
        System.out.println("Car is driving.");
    }
}

3. XML-based Configuration

Define beans in beans.xml:

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="engine" class="com.example.Engine" />

    <bean id="car" class="com.example.Car">
        <property name="engine" ref="engine" />
    </bean>

</beans>

Test the configuration:

public class App {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        
        Car car = context.getBean("car", Car.class);
        car.drive();
    }
}

4. Annotation-based Configuration

Use annotations for DI:

Engine class remains the same. Update the Car class:

@Component
public class Car {
    @Autowired
    private Engine engine;

    // rest of the class remains unchanged
}

Create a configuration class:

@Configuration
@ComponentScan(basePackages = "com.example")
public class AppConfig {
}

Test the configuration:

public class App {
    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
        
        Car car = context.getBean(Car.class);
        car.drive();
    }
}

In both tests (XML and annotation), when you run the App class, it should print:

Engine started.
Car is driving.

This demonstrates how the Car bean got its dependency (Engine) injected by Spring, either via XML configuration or annotations.

  1. Constructor-based Dependency Injection in Spring example:

    • Description: Constructor-based DI involves injecting dependencies through the constructor of a class. It ensures that the class is initialized with all required dependencies.
    • Code:
      public class MyService {
          private final MyRepository myRepository;
      
          public MyService(MyRepository myRepository) {
              this.myRepository = myRepository;
          }
      }
      
  2. Setter-based Dependency Injection in Spring example:

    • Description: Setter-based DI involves injecting dependencies through setter methods. It provides flexibility as dependencies can be changed after the object is created.
    • Code:
      public class MyService {
          private MyRepository myRepository;
      
          public void setMyRepository(MyRepository myRepository) {
              this.myRepository = myRepository;
          }
      }
      
  3. Field-based Dependency Injection in Spring example:

    • Description: Field-based DI involves injecting dependencies directly into fields. While concise, it may limit flexibility and is not recommended for mandatory dependencies.
    • Code:
      public class MyService {
          @Autowired
          private MyRepository myRepository;
      }
      
  4. Autowired annotation in Spring Dependency Injection:

    • Description: The @Autowired annotation is used in Spring to automatically inject dependencies. It can be applied to fields, constructors, or setter methods.
    • Code:
      public class MyService {
          @Autowired
          private MyRepository myRepository;
      }
      
  5. Qualifiers and Named dependencies in Spring DI:

    • Description: When multiple beans of the same type exist, use @Qualifier to specify the bean to inject. Alternatively, use @Named annotation for named dependencies.

    • Code:

      public class MyService {
          @Autowired
          @Qualifier("specificRepository")
          private MyRepository myRepository;
      }
      
      @Component("specificRepository")
      public class SpecificRepository implements MyRepository {
          // Implementation
      }
      
  6. Profiles in Spring Dependency Injection:

    • Description: Profiles enable the configuration of beans for specific environments. It helps in defining different sets of beans for different profiles.

    • Code:

      @Configuration
      @Profile("dev")
      public class DevDataSourceConfig {
          // Configuration for development profile
      }
      
      @Configuration
      @Profile("prod")
      public class ProdDataSourceConfig {
          // Configuration for production profile
      }