Spring Framework Tutorial
Software Setup and Configuration (STS/Eclipse/IntelliJ)
Core Spring
Spring Annotations
Spring Data
Spring JDBC
Spring Security
Inversion of Control (IoC) is a design principle where the control of the flow of a program is inverted: instead of the program code dictating how and when specific tasks are done, a framework or container makes these decisions. In the context of the Spring framework, IoC refers to the Spring container taking care of creating and managing beans.
The primary advantage of IoC is that it promotes decoupling, making code easier to test and maintain.
Let's walk through a basic example of IoC using Spring.
Interface - A simple service interface:
public interface MessageService { void sendMessage(String msg, String recipient); }
Implementation - Implementation of the service interface:
public class EmailService implements MessageService { @Override public void sendMessage(String msg, String recipient) { // Logic to send an email System.out.println("Email sent to " + recipient + " with message=" + msg); } }
Consumer - A consumer class which depends on the MessageService
:
public class MessageServiceConsumer { private MessageService service; // Constructor-based dependency injection public MessageServiceConsumer(MessageService svc) { this.service = svc; } public void processMessage(String msg, String recipient) { this.service.sendMessage(msg, recipient); } }
Now, you would configure the Spring container to manage these beans using 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"> <!-- Message Service bean --> <bean id="messageService" class="EmailService" /> <!-- Message Consumer bean --> <bean id="consumer" class="MessageServiceConsumer"> <constructor-arg ref="messageService"/> </bean> </beans>
Now, let's test our configuration to see IoC in action:
import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class IoCExample { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml"); MessageServiceConsumer consumer = (MessageServiceConsumer) context.getBean("consumer"); consumer.processMessage("Hello, IoC!", "test@domain.com"); } }
When you run the IoCExample
, you should see the message indicating that an email was sent.
In this example, the MessageServiceConsumer
doesn't create an instance of EmailService
directly. Instead, it's handed to it (injected) by the Spring container - this is the Inversion of Control. The benefit is that you can change the MessageService
implementation (e.g., switch to an SMSService
) without modifying the MessageServiceConsumer
class, only the Spring configuration.
Using constructor injection in Spring IoC:
public class MyService { private final MyRepository myRepository; public MyService(MyRepository myRepository) { this.myRepository = myRepository; } }
Setter injection in Spring IoC container:
public class MyService { private MyRepository myRepository; public void setMyRepository(MyRepository myRepository) { this.myRepository = myRepository; } }
IoC container configuration in Spring XML:
<beans> <bean id="myService" class="com.example.MyService"> <property name="myRepository" ref="myRepository"/> </bean> <bean id="myRepository" class="com.example.MyRepository"/> </beans>
Annotation-based configuration for IoC in Spring:
@Service public class MyService { @Autowired private MyRepository myRepository; }
IoC container initialization and destruction methods:
public class MyService { @PostConstruct public void init() { // Initialization logic } @PreDestroy public void cleanup() { // Destruction logic } }
Configuring beans with JavaConfig in Spring IoC:
@Configuration public class AppConfig { @Bean public MyService myService() { return new MyService(myRepository()); } @Bean public MyRepository myRepository() { return new MyRepository(); } }