How Does ApplicationContext Create Beans in Spring?

Liu yuLiu yu
3 min read

A Deep Dive into ApplicationContext and the Bean Lifecycle

“Don’t just use annotations—understand the architecture.”


1. Why You Should Care

Many Java developers can sprinkle @Autowired and @Bean everywhere—but very few truly grasp what happens under the hood. If you only know “how” to use Spring and not “why” it works that way, you’re building on sand. In this article, we’ll reconstruct Spring’s bean-creation process step by step, so you can:

  • Go beyond CRUD and speak the language of framework authors.
  • Debug Spring source code with confidence.
  • Move from “annotation user” to “architecture thinker.”

2. The Single Line That Changes Everything

ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
`

That one line kicks off an orchestration of scanners, processors, and factories. Let’s unpack it.


3. The Full Bean-Creation Workflow

3.1. Parse Configuration & Register Bean Definitions

  • Scan for Annotations Spring uses ConfigurationClassPostProcessor (and friends) to locate:

    • @Configuration classes

    • @Component, @Service, @Repository

    • @Bean methods

  • Generate BeanDefinition Objects Each discovered component becomes a BeanDefinition, capturing:

    • Bean class or factory method

    • Scope (singleton, prototype, etc.)

    • Dependencies, lazy flags, custom init/destroy methods

  • Store in BeanFactory Registry All BeanDefinitions live in an internal registry inside DefaultListableBeanFactory.

3.2. Refresh the Context

Calling refresh() on AnnotationConfigApplicationContext triggers:

  1. invokeBeanFactoryPostProcessors()

    • Allows code to modify or add definitions before beans are created (e.g. @PropertySource, custom post-processors).
  2. registerBeanPostProcessors()

    • Registers BeanPostProcessor instances (e.g. for AOP proxies, @Transactional).
  3. finishBeanFactoryInitialization()

    • Pre-instantiates all singleton beans by calling getBean() on each definition.

3.3. Instantiate Beans (createBean())

When getBean(name) is invoked (during refresh or by client code), Spring runs AbstractAutowireCapableBeanFactory#createBean():

  1. Instantiate

    • Choose constructor or factory method

    • Use reflection to invoke it

  2. Populate Properties

    • Inject dependencies via field, setter, or constructor injection (@Autowired, @Value)
  3. Apply Initialization Callbacks

    • Methods annotated @PostConstruct

    • Interfaces like InitializingBean.afterPropertiesSet()

    • Custom init-method

  4. Invoke BeanPostProcessor Hooks

    • postProcessBeforeInitialization()

    • AOP proxies are often created here

    • postProcessAfterInitialization()

  5. Return Fully Initialized Instance

3.4. Cache Singleton Beans

  • Singleton Cache (Level 1) holds fully initialized beans.

  • Early-Reference Cache (Level 2) and Factory Cache (Level 3) handle circular dependencies.


4. Visual Summary

@Configuration + @ComponentScan
        ↓
  parse to BeanDefinition
        ↓
 register in BeanFactory
        ↓
   ctx.refresh()
        ↓
  invokeBeanFactoryPostProcessors()
        ↓
 registerBeanPostProcessors()
        ↓
finishBeanFactoryInitialization()
        ↓
    for each bean:
    getBean() → createBean()
        ↓
  - instantiate (reflection)
  - inject dependencies
  - initialize callbacks
  - apply post processors (AOP)
        ↓
 put into singleton cache

5. What You’ll Gain

  • Clarity on why Spring chooses proxy-based AOP.

  • Ability to debug container start-up and bean wiring without panic.

  • Confidence to extend Spring (custom scopes, processors).

  • A solid foundation for teaching, architecting, or contributing to framework code.


6. Next Steps: How to Solidify Your Knowledge

  1. Set Breakpoints in Your IDE

    • In AnnotationConfigApplicationContext.refresh()

    • Step through to DefaultListableBeanFactory.preInstantiateSingletons() and into createBean().

  2. Write Your Own Mini-Container

    • Support: class scanning, simple dependency injection via reflection.

    • Compare your code with Spring’s implementation.

  3. Blog or Teach

    • Draft your own article or internal talk.

    • Explaining concepts to others is the fastest way to master them.

  4. Deepen Related Topics

    • Read “Java Concurrency in Practice” for thread safety in bean creation.

    • Explore the “Spring Framework Reference” on custom BeanPostProcessor and scopes.

  5. Daily Micro-Challenges

    • Pick one method (e.g., postProcessAfterInitialization) each day.

    • Trace its call graph and write a one-paragraph summary.

0
Subscribe to my newsletter

Read articles from Liu yu directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Liu yu
Liu yu