Spring Boot Interview Questions
Spring Boot
Java
BackendWeb DevelopmentQuestion 8
What is dependency injection, and how does Spring Boot support it?
Answer:
Dependency Injection (DI) is a design pattern used to implement Inversion of Control (IoC), allowing the creation and management of dependencies outside of the dependent objects. It decouples the creation of objects and their dependencies from the business logic, making code more modular, testable, and maintainable.
Key Concepts of Dependency Injection
- Inversion of Control (IoC): The control of object creation and dependency management is inverted from the dependent object itself to an external framework or container.
- Dependency: An object that another object requires to function.
- Injection: The process of passing (injecting) the dependencies into the dependent object.
Types of Dependency Injection
- Constructor Injection: Dependencies are provided through the class constructor.
- Setter Injection: Dependencies are provided through setter methods.
- Field Injection: Dependencies are directly assigned to fields (less common due to visibility and testability concerns).
How Spring Boot Supports Dependency Injection
Spring Boot, built on the Spring Framework, provides comprehensive support for dependency injection through its IoC container. Here are the main ways Spring Boot supports DI:
-
Annotation-Based Configuration:
- @Component: Indicates that a class is a Spring-managed component.
- @Autowired: Marks a constructor, field, or setter method to be injected with a dependency.
- @Service, @Repository, @Controller: Specialized annotations for specific types of components.
-
Java-Based Configuration:
- @Configuration: Indicates that a class contains bean definitions.
- @Bean: Declares a bean within a
@Configuration
class.
-
XML-Based Configuration (Less common in Spring Boot):
- Beans can be defined and wired together using XML configuration files.
Example: Dependency Injection in Spring Boot
Step 1: Define Components
Define service and repository components using @Service
and @Repository
annotations.
import org.springframework.stereotype.Service;
@Service
public class MyService {
private final MyRepository myRepository;
@Autowired
public MyService(MyRepository myRepository) {
this.myRepository = myRepository;
}
public String performService() {
return myRepository.getData();
}
}
import org.springframework.stereotype.Repository;
@Repository
public class MyRepository {
public String getData() {
return "Hello from MyRepository";
}
}
Step 2: Autowire Dependencies
Spring Boot will automatically wire the dependencies by scanning for components and injecting them where required.
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.beans.factory.annotation.Autowired;
@SpringBootApplication
public class DemoApplication implements CommandLineRunner {
private final MyService myService;
@Autowired
public DemoApplication(MyService myService) {
this.myService = myService;
}
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
@Override
public void run(String... args) throws Exception {
System.out.println(myService.performService());
}
}
In this example:
MyService
depends onMyRepository
.- The
@Autowired
annotation is used to injectMyRepository
intoMyService
. - The
DemoApplication
class, annotated with@SpringBootApplication
, autowiresMyService
and uses it in therun
method.
Constructor Injection vs. Field Injection
Constructor Injection is generally preferred because:
- It makes dependencies explicit and ensures that the object is fully initialized with all required dependencies.
- It facilitates easier testing by allowing dependencies to be injected through the constructor.
- It helps in creating immutable objects.
Field Injection can be simpler but has some downsides:
- It hides dependencies from the object's API, making it less clear what the object depends on.
- It can lead to issues with immutability and testing.
Example: Constructor Injection
@Service
public class MyService {
private final MyRepository myRepository;
@Autowired
public MyService(MyRepository myRepository) {
this.myRepository = myRepository;
}
public String performService() {
return myRepository.getData();
}
}
Example: Field Injection
@Service
public class MyService {
@Autowired
private MyRepository myRepository;
public String performService() {
return myRepository.getData();
}
}
Using @Configuration
and @Bean
You can also define beans explicitly using Java-based configuration.
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AppConfig {
@Bean
public MyService myService() {
return new MyService(myRepository());
}
@Bean
public MyRepository myRepository() {
return new MyRepository();
}
}
Summary
- Dependency Injection (DI): A design pattern that provides dependencies to objects from an external source.
- Spring Boot Support:
- Annotation-Based:
@Component
,@Service
,@Repository
,@Autowired
. - Java-Based Configuration:
@Configuration
and@Bean
.
- Annotation-Based:
- Constructor Injection: Preferred for its clarity, immutability, and testability.
- Field Injection: Simpler but less explicit and harder to test.
- Configuration and Bean Definition: Allows explicit bean definitions and wiring using configuration classes.
Spring Bootβs support for dependency injection simplifies the development of loosely-coupled, maintainable, and testable applications by managing the lifecycle and dependencies of beans in the application context.