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
Dependency Injection (DI) is a core concept in Spring, allowing you to inject dependencies into Spring beans. The Spring container is responsible for the creation, initialization, and assembly of beans. There are multiple ways to inject dependencies in Spring, one of which is setter-based injection.
Here's a step-by-step guide to perform Dependency Injection via setter methods in a traditional Spring application (non-Spring Boot):
First, let's define two simple classes, Author
and Book
.
public class Author { private String name; // Getter and setter methods public String getName() { return name; } public void setName(String name) { this.name = name; } } public class Book { private String title; private Author author; // Getter and setter methods for both properties public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public Author getAuthor() { return author; } public void setAuthor(Author author) { this.author = author; } }
In a Spring XML configuration file (e.g., beans.xml
):
<?xml version="1.0" encoding="UTF-8"?> <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"> <!-- Definition for author bean --> <bean id="authorBean" class="com.example.Author"> <property name="name" value="John Doe"/> </bean> <!-- Definition for book bean --> <bean id="bookBean" class="com.example.Book"> <property name="title" value="Spring in Action"/> <property name="author" ref="authorBean"/> <!-- Setter-based DI here --> </bean> </beans>
Notice the use of the <property>
tag which defines the property of the bean to inject.
To validate the configuration and ensure that the injection works as expected, write a simple test:
import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class App { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml"); Book book = (Book) context.getBean("bookBean"); System.out.println("Book Title: " + book.getTitle()); System.out.println("Author: " + book.getAuthor().getName()); } }
Running the above App
class should display the book title and author name, proving that the dependencies were injected properly.
Setter-based DI is realized by calling setter methods on your beans after invoking a no-argument constructor to instantiate the bean.
Constructor-based DI is another common way to inject dependencies using the bean's constructor.
It's a best practice not to mix both setter-based and constructor-based DI for the same bean. If you do mix them, the constructor injection happens first.
Spring's DI helps decouple the configuration and specification of application objects from the actual program logic, allowing for cleaner and more modular code.
Setter-based dependency injection in Spring:
public class MyService { private MyRepository myRepository; public void setMyRepository(MyRepository myRepository) { this.myRepository = myRepository; } // Other methods using myRepository }
Configuring beans and dependencies using setters in Spring:
Description: Configure beans and their dependencies in the Spring context XML or JavaConfig. Set the dependencies through setters during the bean configuration.
Code:
<!-- XML Configuration --> <bean id="myService" class="com.example.MyService"> <property name="myRepository" ref="myRepository"/> </bean>
// JavaConfig Configuration @Configuration public class AppConfig { @Bean public MyService myService() { MyService service = new MyService(); service.setMyRepository(myRepository()); return service; } @Bean public MyRepository myRepository() { return new MyRepository(); } }
Optional and required dependencies in setter injection with Spring:
public class MyService { private MyRepository myRepository; // Required dependency public void setMyRepository(MyRepository myRepository) { this.myRepository = myRepository; } // Optional dependency public void setOptionalDependency(MyOptionalService optionalService) { // Logic to handle optional dependency } }
Qualifiers and named dependencies in setter injection with Spring:
Description: Use @Qualifier
annotation to specify which bean to inject when there are multiple candidates. Alternatively, provide a name to the setter method.
Code:
public class MyService { private MyRepository myRepository; @Autowired @Qualifier("specificRepository") public void setMyRepository(MyRepository myRepository) { this.myRepository = myRepository; } }
public class MyService { private MyRepository myRepository; public void setSpecificRepository(MyRepository myRepository) { this.myRepository = myRepository; } }
Using @Value annotation with setter injection in Spring:
@Value
annotation with setter methods.public class MyService { private String apiKey; @Value("${api.key}") public void setApiKey(String apiKey) { this.apiKey = apiKey; } }
Testing and mocking dependencies in Spring with setter injection:
public class MyServiceTest { @Test public void testServiceLogic() { MyService myService = new MyService(); MyRepository mockRepository = Mockito.mock(MyRepository.class); myService.setMyRepository(mockRepository); // Test service logic } }
Setter injection vs. constructor injection in the Spring framework:
Description: Choose between setter injection and constructor injection based on your design preferences and requirements. Constructor injection is often preferred for mandatory dependencies, while setter injection allows for flexibility.
Code: (Comparison)
// Setter Injection public class MyService { private MyRepository myRepository; public void setMyRepository(MyRepository myRepository) { this.myRepository = myRepository; } }
// Constructor Injection public class MyService { private final MyRepository myRepository; public MyService(MyRepository myRepository) { this.myRepository = myRepository; } }