PrepZone Logo
PrepZone

The IoC Container and Spring Beans

How the ApplicationContext creates, wires and manages your objects.

Why this matters

  • Every @Service, @Repository, and @Controller in BookStore is a bean managed by the container — not created with new.
  • Misunderstanding bean lifecycle leads to NullPointerException from field injection or duplicate instances from manual construction.
  • Container internals are a core Spring interview topic; explaining bean creation order demonstrates real framework knowledge.

What is a bean?

A bean is any object whose lifecycle Spring controls. For BookStore:

Java
@Service
public class BookService {
    private final BookRepository repository;

    public BookService(BookRepository repository) {
        this.repository = repository;
    }
}

Spring instantiates BookService once, injects the BookRepository bean, and reuses that same instance for every HTTP request.

Bean registration methods

  • Component scanning — @Service, @Component, @Repository, @Controller on a class.
  • @Bean methods — Explicit factory methods inside @Configuration classes.
  • Auto-configuration — Boot creates beans like DataSource when starters are on the classpath.
ApplicationContext
BookController@RestController
BookService@Service
BookRepository@Repository
DataSourceAuto-configured

Arrows show @Autowired wiring — container injects at startup

The ApplicationContext reads configuration, creates beans, and wires dependencies automatically.

ApplicationContext vs BeanFactory

BeanFactory is the low-level interface for bean retrieval. ApplicationContext extends it with:

ApplicationContext extras

  • Automatic BeanPostProcessor registration
  • Message source internationalisation
  • Event publication (ApplicationEventPublisher)
  • Resource loading from classpath

Boot uses AnnotationConfigServletWebServerApplicationContext — you never instantiate it directly.

Bean definition and creation

At startup the container processes bean definitions — metadata describing how to build each bean:

Bean creation pipeline

  1. Scan — Find @Component classes in com.example.bookstore.**
  2. Parse — Read constructor parameters as injection points
  3. Sort — Order beans to satisfy dependencies (topological sort)
  4. Instantiate — Call constructors, apply @Autowired where needed
  5. Initialise — Run @PostConstruct, InitializingBean.afterPropertiesSet()
  6. Register — Store in the singleton cache

If BookService depends on BookRepository which depends on DataSource, the container creates them in that order automatically.

Retrieving beans programmatically

Rarely needed in application code, but useful in tests:

Java
@SpringBootTest
class BeanInspectionTest {
    @Autowired
    private ApplicationContext context;

    @Test
    void bookServiceIsSingleton() {
        BookService a = context.getBean(BookService.class);
        BookService b = context.getBean(BookService.class);
        assertSame(a, b);
    }
}

Both references point to the same object — default scope is singleton.

When the container fails

Circular dependencies crash startup:

Java
@Service
public class OrderService {
    public OrderService(BookService bookService) { ... }
}

@Service
public class BookService {
    public BookService(OrderService orderService) { ... }  // cycle!
}

Spring detects the cycle and throws BeanCurrentlyInCreationException. Fix by restructuring dependencies or using @Lazy on one side.

Bean naming

Default bean name is the decapitalised class name: bookService for BookService. Override with @Service("catalogService") when multiple implementations exist.

Java
public interface BookRepository { ... }

@Repository
public class JpaBookRepository implements BookRepository { ... }

Injection by type works when only one implementation exists. Multiple implementations require @Qualifier or @Primary.

Context refresh and shutdown

In production the context starts once and runs until shutdown. @PreDestroy methods clean up resources:

Java
@Service
public class CacheWarmupService {
    @PreDestroy
    public void shutdown() {
        // flush pending cache writes
    }
}

Boot registers a shutdown hook so SIGTERM triggers graceful bean destruction.

Quick recall

Everything you need if you only revisit this box.

  • Beans are objects whose lifecycle and dependencies the ApplicationContext manages.
  • Default scope is singleton — one instance per application context.
  • Registration via component scanning (@Service) or explicit @Bean methods.
  • The container topologically sorts dependencies and fails fast on circular references.
  • Never use new for Spring-managed services; injection provides wired instances.
  • ApplicationContext extends BeanFactory with events, resources, and post-processors.

Test yourself

Answer these before moving on — recall is what makes it stick.