Understanding Spring Framework: IoC, AOP, and Modular Design with Java Example

This article explains the purpose of using a framework, introduces Spring's core concepts of container, inversion of control, and aspect‑oriented programming, and demonstrates them through a Java banking report example with complete code, XML configuration, and annotation‑based AOP to achieve loose coupling and modularity.

Java Captain
Java Captain
Java Captain
Understanding Spring Framework: IoC, AOP, and Modular Design with Java Example

As software systems grow larger and require modularization and team collaboration, frameworks help enforce low‑coupling and high‑cohesion design principles; Spring is a lightweight J2EE framework that provides a container, inversion of control (IoC), and aspect‑oriented programming (AOP) to achieve these goals.

1. Meaning of a Framework and Main Content of Spring

Frameworks encapsulate common design patterns and reusable code, allowing developers to focus on business logic while ensuring extensibility, testability, maintainability, and clear module boundaries.

Spring consists of three core parts:

Container

Inversion of Control (IoC)

Aspect‑Oriented Programming (AOP)

2. Simple Example Program

A bank needs to generate monthly statements for customers either as printed paper or SMS, and log each method call for audit purposes.

Interface definition:

public interface ReportGenerator{
    public void generate(String[][] table);
}

Implementation for paper report:

public class PageReportGenerator implements ReportGenerator {
    public void generate(String[][] table) {
        log4j.info(...); // log start
        // print operation
        log4j.info(...); // log end
    }
}

Implementation for SMS report:

public class SMSReportGenerator implements ReportGenerator {
    public void generate(String[][] table) {
        log4j.info(...); // log start
        // send SMS operation
        log4j.info(...); // log end
    }
}

Service class that uses the generator:

public class ReportService{
    private ReportGenerator reportGenerator = new SMSReportGenerator();
    public void generateMonthlyReport(int year, int month){
        log4j.info(...);
        String[][] statistics = null; // compute statistics
        reportGenerator.generate(statistics);
    }
}

3. Spring Container

To eliminate direct dependencies, a simple container can store components and provide them on demand:

public class Container {
    public static Container instance;
    private Map<String, Object> components;
    public Container(){
        components = new HashMap<>();
        instance = this;
        ReportGenerator reportGenerator = new SMSReportGenerator();
        components.put("reportGenerator", reportGenerator);
        ReportService reportService = new ReportService();
        components.put("reportService", reportService);
    }
    public Object getComponent(String id){
        return components.get(id);
    }
}

After using the container, the service obtains its generator via:

private ReportGenerator reportGenerator = (ReportGenerator) Container.instance.getComponent("reportGenerator");

4. Spring Inversion of Control

Even with a container, the service still knows the container’s name, which is a hidden dependency. IoC solves this by letting the container inject the dependency, typically through a setter method:

public class ReportService{
    private ReportGenerator reportGenerator;
    public void setReportGenerator(ReportGenerator reportGenerator){
        this.reportGenerator = reportGenerator;
    }
    // generateMonthlyReport(...) unchanged
}

Spring’s XML configuration can declare beans and their relationships:

<?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-3.0.xsd">
    <bean id="smsReportGenerator" class="bank.SMSReportGenerator"/>
    <bean id="reportService" class="bank.ReportService">
        <property name="reportGenerator" ref="smsReportGenerator"/>
    </bean>
</beans>

5. Spring Aspect‑Oriented Programming

Logging code scattered across methods is a cross‑cutting concern. AOP modularizes it using aspects. First, a logging aspect defined with annotations:

@Aspect
public class LogAspect {
    @Before("execution(* *.*(..))")
    public void LogBefore(JoinPoint joinPoint) throws Throwable {
        log4j.info("Start: " + joinPoint.getSignature().getName());
    }
    @After("execution(* *.*(..))")
    public void LogAfter(JoinPoint joinPoint) throws Throwable {
        log4j.info("End: " + joinPoint.getSignature().getName());
    }
}

Spring’s AOP XML adds the necessary namespace and enables auto‑proxying:

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
                           http://www.springframework.org/schema/aop
                           http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
    <aop:aspectj-autoproxy/>
    <bean id="smsReportGenerator" class="bank.SMSReportGenerator"/>
    <bean id="reportService" class="bank.ReportService">
        <property name="reportGenerator" ref="smsReportGenerator"/>
    </bean>
    <bean class="bank.LogAspect"/>
</beans>

With this configuration, Spring automatically weaves the logging aspect into all methods, removing the need for manual log statements.

6. Summary

By applying Spring’s container, IoC, and AOP to the banking statement example, the original tightly‑coupled code is refactored into three loosely‑coupled modules—service, generator, and container—making the system easier to understand, extend, test, and maintain.

Original source: my.oschina.net/myriads/blog/37922

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaaopIoCspringdependency-injectionmodular design
Java Captain
Written by

Java Captain

Focused on Java technologies: SSM, the Spring ecosystem, microservices, MySQL, MyCat, clustering, distributed systems, middleware, Linux, networking, multithreading; occasionally covers DevOps tools like Jenkins, Nexus, Docker, ELK; shares practical tech insights and is dedicated to full‑stack Java development.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.