Understanding Spring’s Core Concepts: IoC, DI, AOP and Bean Management
The article explains how Spring’s IoC container, dependency injection, singleton beans, and AOP simplify Java backend development by abstracting object creation, configuration, and cross‑cutting concerns, illustrated with code examples and practical scenarios such as conditional bean loading and Redis client selection.
When the author first learned Java, they manually instantiated services using new ServiceB() , which quickly became unmanageable as the number of services and dependencies grew, especially when adding features like transactions or logging.
SpringBoot reduced XML configuration, but without a clear strategy the author still struggled to modify beans. Moving to SpringCloud highlighted the need for a higher‑level view of the framework.
To avoid repetitive new statements, the author introduced a singleton pattern:
public class ServiceA {
private ServiceB serviceB = ServiceB.getInstance();
}
public class ServiceB {
private static ServiceB instance = new ServiceB(new ServiceC());
private ServiceB() {}
public static ServiceB getInstance() { return instance; }
}While this solves the immediate problem, it does not scale for enterprise applications where dozens or hundreds of services depend on each other and need features like transaction management.
Spring solves these issues by acting as a machine that reads configuration (XML or @Configuration classes) and automatically creates and wires beans. Developers declare dependencies (e.g., @Autowired ServiceB serviceB; ) without writing the instantiation code.
This mechanism is known as Inversion of Control (IoC). Spring stores singleton beans in a map, allowing retrieval by name or type, and provides extension points such as BeanFactoryPostProcessor and BeanPostProcessor for custom behavior.
Aspect‑Oriented Programming (AOP) further reduces boilerplate: annotating a method with @Transactional lets Spring weave transaction handling automatically, and a global logging aspect can record request parameters for all controllers.
Conditional bean loading is demonstrated with Redis client selection. SpringBoot’s auto‑configuration prefers lettuce unless a bean of type RedisConnectionFactory is missing, in which case jedis is injected. The Maven snippet shows how to exclude lettuce and include jedis :
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<exclusions>
<exclusion>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>In summary, Spring’s core concepts—IoC, DI, and AOP—provide a flexible, reusable foundation that eliminates repetitive code, manages bean lifecycles, and enables easy extension through configuration and custom processors.
Architect
Professional architect sharing high‑quality architecture insights. Topics include high‑availability, high‑performance, high‑stability architectures, big data, machine learning, Java, system and distributed architecture, AI, and practical large‑scale architecture case studies. Open to ideas‑driven architects who enjoy sharing and learning.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.