Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Complete Spring IoC Resource Guide

Tech 2
  1. IoC (Inversion of Control)/DI (Dependency Injection)
  2. AOP (Aspect-Oriented Programming)

Spring Overview

Spring is an enterprise-level development framework focused on software design, offering flexible component selection and application layer separation.

MVC: Struts2, Spring MVC
ORMapping: Hibernate, MyBatis, Spring Data

Why Use Spring (Enterprise Project Characteristics)

  1. Large scale: high user count, massive data, numerous functional modules
  2. High performance and security requiremants
  3. Complex business logic
  4. Frequent changes

Spring Advantages

  1. Low intrusive design
  2. Independence from application servers
  3. Dependency injection simplifies component relationships and reduces coupling
  4. Aspect-oriented programming enables centralized handling of common tasks
  5. Excellent integration with third-party frameworks

Spring IoC

What is Inversion of Control

In traditional development, the caller actively creates instances of called objects. In Spring, the IoC container manages object creation and pushes instances to callers, reversing the control flow.

How to Use IoC

Maven Project Setup

<?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>SpringDemo</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>6.0.12</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.20</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>
</project>

Create Entity Class

package com.example.entity;
import lombok.Data;
@Data
public class Person {
    private String fullName;
    private long personId;
    private int age;
    private Location residence;
}
package com.example.entity;
import lombok.Data;
@Data
public class Location {
    private long locationId;
    private String address;
}

Traditional vs IoC Approach

Traditional (Manual Creation):

Person person = new Person();
person.setPersonId(101);
person.setFullName("Alice Smith");
person.setAge(30);
System.out.println(person);

IoC Configuration (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="myPerson" class="com.example.entity.Person">
        <property name="personId" value="101"></property>
        <property name="fullName" value="Alice Smith"></property>
        <property name="age" value="30"></property>
        <property name="residence" ref="myLocation"></property>
    </bean>

    <bean id="myLocation" class="com.example.entity.Location">
        <property name="locationId" value="5001"></property>
        <property name="address" value="123 Main St, NY"></property>
    </bean>
</beans>

Retrieve Object from IoC:

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.example.entity.Person;

public class IoCTest {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        Person person = (Person) context.getBean("myPerson");
        System.out.println(person);
    }
}

Configuration File Details

  • bean tag: manages objects
    • id: object identifier
    • class: fully qualified class name (requires no-arg constructor for reflection)
  • property tag: injects properties
    • name: property name
    • value: for primitive types and String
    • ref: references another bean (DI)

IoC Underlying Principles

Implement a simplified IoC container using DOM4J and reflection:

Add DOM4J Dependency

<dependency>
    <groupId>dom4j</groupId>
    <artifactId>dom4j</artifactId>
    <version>2.1.3</version>
</dependency>

Implement ApplicationContext

package com.example.ioc;

public interface ApplicationContext {
    Object getBean(String beanId);
}

Implement ClassPathXmlApplicationContext

package com.example.ioc;

import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

public class ClassPathXmlApplicationContext implements ApplicationContext {
    private Map<String, Object> iocContainer = new HashMap<>();

    public ClassPathXmlApplicationContext(String configPath) throws Exception {
        SAXReader reader = new SAXReader();
        Document document = reader.read("./src/main/resources/" + configPath);
        Element root = document.getRootElement();
        Iterator<Element> beanIterator = root.elementIterator();

        while (beanIterator.hasNext()) {
            Element bean = beanIterator.next();
            String beanId = bean.attributeValue("id");
            String className = bean.attributeValue("class");

            Class<?> clazz = Class.forName(className);
            Constructor<?> constructor = clazz.getConstructor();
            Object instance = constructor.newInstance();

            Iterator<Element> propertyIterator = bean.elementIterator();
            while (propertyIterator.hasNext()) {
                Element property = propertyIterator.next();
                String propName = property.attributeValue("name");
                String propValue = property.attributeValue("value");
                String propRef = property.attributeValue("ref");

                if (propRef == null) {
                    String setterName = "set" + propName.substring(0, 1).toUpperCase() + propName.substring(1);
                    Field field = clazz.getDeclaredField(propName);
                    Method setter = clazz.getDeclaredMethod(setterName, field.getType());

                    Object convertedValue = null;
                    String fieldType = field.getType().getName();
                    if (fieldType.equals("long")) {
                        convertedValue = Long.parseLong(propValue);
                    } else if (fieldType.equals("java.lang.String")) {
                        convertedValue = propValue;
                    } else if (fieldType.equals("int")) {
                        convertedValue = Integer.parseInt(propValue);
                    }
                    setter.invoke(instance, convertedValue);
                }
            }
            iocContainer.put(beanId, instance);
        }
    }

    @Override
    public Object getBean(String beanId) {
        return iocContainer.get(beanId);
    }
}

Test Custom IoC

import com.example.entity.Person;
import com.example.ioc.ApplicationContext;
import com.example.ioc.ClassPathXmlApplicationContext;

public class CustomIoCTest {
    public static void main(String[] args) throws Exception {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        Person person = (Person) context.getBean("myPerson");
        System.out.println(person);
    }
}

Bean Scopes

  • singleton (default): single instence per IoC container
  • prototype: new instance for each request
  • request: valid within an HTTP request
  • session: valid within a user session

Spring Inheritance

Object-level inheritance: child bean inherits parent bean's properties (class can differ if properties match)

<bean id="basePerson" class="com.example.entity.Person">
    <property name="personId" value="200"></property>
    <property name="fullName" value="Base User"></property>
</bean>

<bean id="extendedPerson" class="com.example.entity.Person" parent="basePerson">
    <property name="age" value="28"></property>
</bean>

Spring Dependency

Specifies creation order: depends-on ensures dependent bean is created first

<bean id="employee" class="com.example.entity.Employee" depends-on="department"></bean>
<bean id="department" class="com.example.entity.Department"></bean>

P Namespace

Simplifies property injection

<?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:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="personBean" class="com.example.entity.Person" 
          p:personId="300" p:fullName="Bob Brown" p:age="35" 
          p:residence-ref="locationBean"></bean>

    <bean id="locationBean" class="com.example.entity.Location" 
          p:locationId="6001" p:address="456 Oak Ave, LA"></bean>
</beans>

Factory Methods

Static Factory

package com.example.factory;

import com.example.entity.Product;
import java.util.HashMap;
import java.util.Map;

public class StaticProductFactory {
    private static Map<Long, Product> productMap;
    static {
        productMap = new HashMap<>();
        productMap.put(100L, new Product(100L, "Laptop"));
        productMap.put(101L, new Product(101L, "Smartphone"));
    }

    public static Product getProduct(long productId) {
        return productMap.get(productId);
    }
}

Config:

<bean id="myProduct" class="com.example.factory.StaticProductFactory" 
      factory-method="getProduct">
    <constructor-arg value="100"></constructor-arg>
</bean>

Instance Factory

package com.example.factory;

import com.example.entity.Product;
import java.util.HashMap;
import java.util.Map;

public class InstanceProductFactory {
    private Map<Long, Product> productMap;

    public InstanceProductFactory() {
        productMap = new HashMap<>();
        productMap.put(200L, new Product(200L, "Tablet"));
        productMap.put(201L, new Product(201L, "Watch"));
    }

    public Product getProduct(long productId) {
        return productMap.get(productId);
    }
}

Config:

<bean id="productFactory" class="com.example.factory.InstanceProductFactory"></bean>
<bean id="myInstanceProduct" factory-bean="productFactory" 
      factory-method="getProduct">
    <constructor-arg value="200"></constructor-arg>
</bean>

Autowiring

Automatically injects dependencies without explicit property tags

byName

Injects by property name matching bean id

<bean id="myPerson" class="com.example.entity.Person" autowire="byName">
    <property name="personId" value="400"></property>
    <property name="fullName" value="Charlie Davis"></property>
</bean>

<bean id="residence" class="com.example.entity.Location">
    <property name="locationId" value="7001"></property>
    <property name="address" value="789 Pine Rd, Chicago"></property>
</bean>

byType

Injects by property type (requires unique bean type)

<bean id="myPerson" class="com.example.entity.Person" autowire="byType">
    <property name="personId" value="400"></property>
    <property name="fullName" value="Charlie Davis"></property>
</bean>

<bean class="com.example.entity.Location">
    <property name="locationId" value="7001"></property>
    <property name="address" value="789 Pine Rd, Chicago"></property>
</bean>
Tags: Spring IoC

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.