Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Understanding Spring IoC Container and Dependency Injection with Bean Configuration Examples

Tech 4

1. Project Structure Overview

Project Structure

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

  1. XML Configuration: Traditional approach shown in examples
  2. Annotation-based: Using @Component, @Service, @Autowired
  3. 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

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.