Understanding Spring IoC Container and Dependency Injection with Bean Configuration Examples
1. Project Structure Overview

2. Code Implementation
(1) Data Access and Service Layer Implementation
DataAccessObject.java
package com.example.dao.impl;
import com.example.dao.DataAccessInterface;
public class DataAccessObject implements DataAccessInterface {
@Override
public void executeOperation() {
System.out.println("Data access layer operation executed...");
}
// Bean lifecycle initialization method
public void initialize() {
// Initialization logic
System.out.println("Bean initialization...");
}
// Bean lifecycle destruction method
public void cleanup() {
// Cleanup logic
System.out.println("Bean cleanup...");
}
}
BusinessService.java
package com.example.service.impl;
import com.example.dao.DataAccessInterface;
import com.example.service.BusinessServiceInterface;
public class BusinessService implements BusinessServiceInterface {
// Dependency injection - no manual instantiation
private DataAccessInterface dataAccess;
// Setter method for dependency injection
public void setDataAccess(DataAccessInterface dataAccess) {
this.dataAccess = dataAccess;
}
@Override
public void performBusinessOperation() {
System.out.println("Business service operation executed...");
// Delegate to data access layer
dataAccess.executeOperation();
}
}
(2) Maven Dependencies Configuration
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>spring-ioc-demo</artifactId>
<version>1.0.0</version>
<dependencies>
<!-- Spring Framework Context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.23</version>
</dependency>
<!-- Unit Testing -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
(3) Spring Bean Configuration
applicationContext.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">
<!-- 1. IoC Configuration: Bean declaration to decouple object creation -->
<!-- Additional aliases can be configured using the name attribute -->
<!-- Lifecycle methods configured via init-method and destroy-method -->
<bean id="dataAccessBean"
name="dao primaryDao"
class="com.example.dao.impl.DataAccessObject"
init-method="initialize"
destroy-method="cleanup"/>
<!-- Scope configuration example (commented out) -->
<!-- <bean id="dataAccessBean"
class="com.example.dao.impl.DataAccessObject"
scope="prototype"/> -->
<!-- 2. Service Bean with Dependency Injection -->
<bean id="businessService"
class="com.example.service.impl.BusinessService">
<!-- Dependency Injection configuration -->
<property name="dataAccess" ref="dataAccessBean"/>
</bean>
<!--
Bean instantiation methods:
1. Constructor instantiation (most common)
2. Static factory instantiation
3. Instance factory instantiation
-->
</beans>
(4) Application Entry Point
ApplicationRunner.java
package com.example;
import com.example.service.BusinessServiceInterface;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class ApplicationRunner {
public static void main(String[] args) {
// Traditional approach without Spring
/*
BusinessService service = new BusinessService();
service.performBusinessOperation();
*/
// Spring IoC Container approach
// 1. Initialize IoC container
ClassPathXmlApplicationContext context =
new ClassPathXmlApplicationContext("applicationContext.xml");
// 2. Retrieve bean from container
BusinessServiceInterface service =
(BusinessServiceInterface) context.getBean("businessService");
// 3. Execute business operation
service.performBusinessOperation();
// 4. Graceful container shutdown
// context.close(); // Immediate shutdown
context.registerShutdownHook(); // JVM shutdown hook
}
}
3. Key Concepts Explained
Inversion of Control (IoC)
The Spring IoC container manages object creation and lifecycle, reversing the traditional control flow where objects create their own dependencies.
Dependency Injection (DI)
Dependencies are provided to objects by the container rather than objects creating them internally, promoting loose coupling and testability.
Bean Lifecycle Management
- Initialization: Custom logic executed after bean property are set
- Destruction: Cleanup operations before bean removal
- Scope Management: Singleton (default) vs Prototype scopes
Configuration Approaches
- XML Configuration: Traditional approach shown in examples
- Annotation-based: Using @Component, @Service, @Autowired
- Java Configuration: @Configuration and @Bean annotations
Best Practices
- Use constructor injection for mandatory dependencies
- Prefer setter injection for optional dependencies
- Configure lifecycle methods for resource management
- Choose appropriate bean scopes based on usage patterns