Fading Coder

One Final Commit for the Last Sprint

Home > Tools > Content

Implementing Dependency Injection with Spring's IOC Container

Tools 2

Spring's Inversion of Control (IOC) is realized through Dependency Enjection (DI), which offers several advantages:

  • Minimizes object creation and management, enhancing code clarity.
  • The lightweight, non-invasive Spring IOC container avoids dependency on container-specific APIs and doesn't require special interface implementations.
  • Encourages programming to interfaces.
  • Reduces code coupling by externalizing dependencies to configuration files, simplifying relationship changes.
  • Provides declarative AOP services.

XML-Based Dependency Injection

XML configuration supports constructor injection, setter injection, and rarely used interface injection. Setter injection is demonstrated below.

Injecting Common POJO Properties

A Plain Old Java Object (POJO) without interfaces or parent classes can have properties injected via XML.

POJO Class:

package com.example.spring.entity;

import java.util.*;

public class Customer {
    private String name;
    private int id;
    private List<String> preferences;
    private Set<String> categories;
    private String[] aliases;
    private Map<String, String> metadata;
    
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    public int getId() { return id; }
    public void setId(int id) { this.id = id; }
    public List<String> getPreferences() { return preferences; }
    public void setPreferences(List<String> preferences) { this.preferences = preferences; }
    public Set<String> getCategories() { return categories; }
    public void setCategories(Set<String> categories) { this.categories = categories; }
    public String[] getAliases() { return aliases; }
    public void setAliases(String[] aliases) { this.aliases = aliases; }
    public Map<String, String> getMetadata() { return metadata; }
    public void setMetadata(Map<String, String> metadata) { this.metadata = metadata; }
}

Configruation File (customer-config.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">
    <bean id="customer" class="com.example.spring.entity.Customer">
        <property name="name" value="John Doe"/>
        <property name="id" value="1001"/>
        <property name="preferences">
            <list>
                <value>Reading</value>
                <value>Traveling</value>
            </list>
        </property>
        <property name="categories">
            <set>
                <value>Premium</value>
                <value>Active</value>
            </set>
        </property>
        <property name="aliases">
            <list>
                <value>JD</value>
                <value>John</value>
            </list>
        </property>
        <property name="metadata">
            <map>
                <entry key="region" value="North"/>
                <entry key="status" value="Verified"/>
            </map>
        </property>
    </bean>
</beans>

Test Class:

package com.example.spring.test;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.example.spring.entity.Customer;

public class PropertyInjectionTest {
    @Test
    public void testPropertyInjection() {
        ApplicationContext context = new ClassPathXmlApplicationContext("customer-config.xml");
        Customer customer = (Customer) context.getBean("customer");
        
        System.out.println("Name: " + customer.getName());
        System.out.println("ID: " + customer.getId());
        System.out.println("Preferences: " + customer.getPreferences());
        System.out.println("Categories: " + customer.getCategories());
        System.out.println("Aliases: " + Arrays.toString(customer.getAliases()));
        System.out.println("Metadata: " + customer.getMetadata());
    }
}

Bean Scope Configuration

The scope attribute defines bean instantiation behavior:

  • singleton: Single instance per container (default).
  • prototype: New instance on each request.

Configuration (scope-config.xml):

<bean id="product" class="com.example.spring.entity.Product" scope="prototype"/>

Test:

ApplicationContext context = new ClassPathXmlApplicationContext("scope-config.xml");
Product prod1 = (Product) context.getBean("product");
Product prod2 = (Product) context.getBean("product");
System.out.println(prod1 == prod2); // false for prototype

Lazy Initialization

Set lazy-init="true" to defer bean creation until first use, or default-lazy-init="true" for all beans in a configurasion.

Configuration (lazy-config.xml):

<bean id="order" class="com.example.spring.entity.Order" lazy-init="true"/>

Autowiring Dependencies

Spring can automatically inject dependencies using autowire:

  • byName: Matches bean ID with property name.
  • byType: Matches bean type (requires autowire-candidate="false" to exclude candidates).

Configuration (autowire-config.xml):

<bean id="accountDao" class="com.example.spring.dao.AccountDaoImpl"/>
<bean id="alternateDao" class="com.example.spring.dao.AlternateDaoImpl" autowire-candidate="false"/>
<bean id="accountService" class="com.example.spring.service.AccountService" autowire="byType"/>

Loading Configuration Files

Single File

ApplicationContext context = new ClassPathXmlApplicationContext("config.xml");
// or
ApplicationContext context = new FileSystemXmlApplicationContext("/absolute/path/config.xml");

Multiple Files

// Array method
String[] files = {"config1.xml", "config2.xml"};
ApplicationContext context = new ClassPathXmlApplicationContext(files);

// Pattern matching
ApplicationContext context = new ClassPathXmlApplicationContext("config-*.xml");

// Master configuration file
ApplicationContext context = new ClassPathXmlApplicationContext("master-config.xml");

Master Configuration (master-config.xml):

<beans>
    <import resource="config1.xml"/>
    <import resource="config2.xml"/>
</beans>

Annotation-Based Dependency Injection

Include spring-aop.jar and configure component scanning.

Configuration (annotation-config.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"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/context
                           http://www.springframework.org/schema/context/spring-context.xsd">
    <context:component-scan base-package="com.example.spring"/>
</beans>

Stereotype Annotations:

  • @Component: Generic component.
  • @Service: Service layer class.
  • @Repository: Data access class.
  • @Controller: Web controller class.
  • @Scope("prototype"): Defines bean scope.

Dependency Injection Annotations:

  • @Autowired: Injects by type, falls back to name.
  • @Qualifier("beanName"): Specifies bean name with @Autowired.
  • @Resource: Injects by name, falls back to type.

Service Class:

package com.example.spring.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.example.spring.dao.PaymentDao;

@Service("paymentService")
public class PaymentService {
    @Autowired
    private PaymentDao paymentDao;
    
    public void setPaymentDao(PaymentDao paymentDao) {
        this.paymentDao = paymentDao;
    }
    
    public boolean processPayment(String account, double amount) {
        return paymentDao.process(account, amount);
    }
}

DAO Implementation:

package com.example.spring.dao.impl;

import org.springframework.stereotype.Repository;
import com.example.spring.dao.PaymentDao;

@Repository("paymentDao")
public class PaymentDaoImpl implements PaymentDao {
    public boolean process(String account, double amount) {
        System.out.println("Processing payment via DAO");
        return true;
    }
}

Test:

ApplicationContext context = new ClassPathXmlApplicationContext("annotation-config.xml");
PaymentService service = (PaymentService) context.getBean("paymentService");
service.processPayment("ACC001", 250.75);

Related Articles

Efficient Usage of HTTP Client in IntelliJ IDEA

IntelliJ IDEA incorporates a versatile HTTP client tool, enabling developres to interact with RESTful services and APIs effectively with in the editor. This functionality streamlines workflows, replac...

Installing CocoaPods on macOS Catalina (10.15) Using a User-Managed Ruby

System Ruby on macOS 10.15 frequently fails to build native gems required by CocoaPods (for example, ffi), leading to errors like: ERROR: Failed to build gem native extension checking for ffi.h... no...

Resolve PhpStorm "Interpreter is not specified or invalid" on WAMP (Windows)

Symptom PhpStorm displays: "Interpreter is not specified or invalid. Press ‘Fix’ to edit your project configuration." This occurs when the IDE cannot locate a valid PHP CLI executable or when the debu...

Leave a Comment

Anonymous

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