Back to posts
Dive Into Spring Core: Mastering DI, Annotations, and IoC

Dive Into Spring Core: Mastering DI, Annotations, and IoC

Madhuka Malshan / April 8, 2025

🌿 Introduction to Spring Core

If you're stepping into the world of Java enterprise development, Spring Core is your gateway. It's the foundation module of the Spring Framework, providing features for dependency injection, bean lifecycle management, and annotation-based configuration.

Let’s dive deep into Spring Core and understand why it's a game-changer for Java developers.


πŸ’‘ What is Spring Core?

Spring Core is a module that gives you the tools to manage the objects (beans) in your application through the concept of Inversion of Control (IoC) and Dependency Injection (DI).


πŸ”„ Inversion of Control (IoC)

Inversion of Control is a principle where the control of object creation and dependency resolution is handed over to the Spring Container, rather than being managed manually in your code.

Think of it like hiring a personal assistant: instead of you remembering to call the plumber, your assistant (Spring) does it for you automatically.


🧩 Dependency Injection (DI)

Dependency Injection is a technique to supply objects (dependencies) a class needs without creating them inside the class. This makes your code:

  • Easier to test
  • Easier to maintain
  • More flexible to extend

🧰 Types of Dependency Injection

1. πŸ§ͺ Constructor Injection (CI)

@Component public class Car { private final Engine engine; @Autowired public Car(Engine engine) { this.engine = engine; } }

βœ… Best for mandatory dependencies
🚫 Slightly verbose if many dependencies


2. πŸ§‘β€πŸ”§ Setter Injection (SI)

@Component public class Car { private Engine engine; @Autowired public void setEngine(Engine engine) { this.engine = engine; } }

βœ… Best for optional dependencies
🚫 Can lead to partially initialized objects


🧠 Real-World Analogy: DI Explained

Imagine you're building a computer:

  • Without DI: You create all parts (CPU, RAM, HDD) inside the computer class.
  • With DI: You receive all parts from an external supplier (Spring) and just assemble them.

πŸ›οΈ IoC Containers: BeanFactory vs ApplicationContext

Spring provides containers that manage the lifecycle of beans.

πŸ”Έ Lazy Initialization

BeanFactory: βœ… Yes

ApplicationContext: ❌ No (eager by default)

πŸ”Έ Internationalization Support

BeanFactory: ❌ No

ApplicationContext: βœ… Yes

πŸ”Έ Event Publishing

BeanFactory: ❌ No

ApplicationContext: βœ… Yes

πŸ”Έ AOP Integration

BeanFactory: ❌ No

ApplicationContext: βœ… Yes


🧬 Bean Scopes in Spring

πŸ”Ή singleton β†’ One instance per Spring container (default)

πŸ”Ή prototype β†’ A new instance is created every time it’s requested

πŸ”Ή request β†’ One instance per HTTP request (for web applications)

πŸ”Ή session β†’ One instance per HTTP session (for web applications)

@Component
@Scope("prototype")
public class Employee {}

πŸ”– Annotations in Spring Core

Basic Annotations

  • @Component – Marks a class as a Spring-managed bean.
  • @Autowired – Injects the dependency automatically.
  • @Qualifier – Helps resolve ambiguity with multiple beans.
  • @Value – Injects primitive values or properties.

πŸ“¦ JSR-250 Annotations

JSR-250 provides Java-standard annotations that Spring supports:

@PostConstruct β†’ This method is called after the bean has been initialized.

@PreDestroy β†’ This method is called right before the bean is destroyed.

@Resource β†’ Injects a dependency by name.


πŸ“¦ JSR-330 Annotations

These are from the javax.inject package:

@Inject β†’ Serves as an alternative to Spring’s @Autowired.

@Named β†’ Can be used in place of @Component.

@Singleton β†’ Ensures that only one instance of the bean is created.


🧬 Bean Lifecycle & Callbacks

The bean lifecycle includes:

  1. Instantiation
  2. Populating properties (DI)
  3. @PostConstruct or afterPropertiesSet()
  4. Bean is ready for use
  5. @PreDestroy or destroy()
@Component public class Service { @PostConstruct public void init() { System.out.println("Initialized!"); } @PreDestroy public void cleanup() { System.out.println("Destroyed!"); } }

βš–οΈ XML vs Annotation-based Config

Spring originally used XML for everything.

<bean id="myService" class="com.app.MyService"/>

Now we use annotations like:

@Component
public class MyService {}

➑️ Annotation-based config is now the standard.


🧠 Best Practices

βœ… Prefer Constructor Injection
βœ… Use @Qualifier for multiple implementations
βœ… Avoid field injection for testability
βœ… Use @PostConstruct instead of custom init methods
βœ… Use interfaces for better decoupling


🚫 Common Pitfalls

❌ Circular Dependencies (A needs B, B needs A)
❌ Mixing too many annotations without structure
❌ Overusing prototype scope in singletons
❌ Injecting optional beans without @Nullable or Optional


βœ… Quick Quiz

  1. Which injection type is better for mandatory dependencies?
  2. What is the default scope of a Spring bean?
  3. Name one annotation from JSR-330.
  4. What's the difference between @Component and @Named?

πŸ“Œ FAQ

Q: Is Spring Core only for web apps?
A: No! Spring Core can be used in any Java application.

Q: Can I mix XML and annotations?
A: Yes, though it's not recommended for large projects.

Q: Is @Inject the same as @Autowired?
A: Functionally, yes – but @Inject is from JSR-330.


🧭 What’s Next?

  • Spring Boot: Simplify Spring setup with auto-configuration
  • Spring AOP: Handle cross-cutting concerns like logging and security
  • Spring Data: Simplify database interactions