The ApplicationContext in Action
The ApplicationContext in Action
You have read about the IoC container and bean definitions in the abstract. Now it is time to write real code: boot an ApplicationContext, pull beans out of it, and understand which concrete implementation to choose in each situation. This lesson focuses on the two things developers do every day with the container — selecting the right ApplicationContext class and retrieving beans correctly.
The Three Core ApplicationContext Implementations
Spring ships with several ApplicationContext implementations. You will encounter three of them constantly:
AnnotationConfigApplicationContext— the standard choice for standalone Java applications, integration tests, and any project that configures Spring with@Configurationclasses and/or component scanning. It does not depend on a servlet container or a classpath resource.ClassPathXmlApplicationContext— loads XML bean definitions from the classpath. You will mainly see this in legacy codebases. Understanding it helps you read older projects and migrate them.GenericWebApplicationContext/AnnotationConfigWebApplicationContext— used inside a Servlet container (Tomcat, Jetty). Spring MVC'sDispatcherServletcreates one of these for you automatically; you rarely construct it by hand.
SpringApplication.run() call boots an AnnotationConfigServletWebServerApplicationContext (or the reactive variant) behind the scenes. You do not call the constructor yourself, but you can still cast the returned ConfigurableApplicationContext to inspect it. Everything covered here applies directly.
Booting the Context: AnnotationConfigApplicationContext
The simplest way to start a Spring container is to pass your @Configuration class to the constructor:
The constructor accepts one or more @Configuration classes, or you can pass a base package name string to enable component scanning:
Use try-with-resources whenever you control the lifecycle. ApplicationContext extends Closeable, so the try block calls close() for you, triggering graceful shutdown of all singleton beans.
Retrieving Beans: Three Overloads of getBean()
The BeanFactory interface (which ApplicationContext extends) exposes several overloads. Knowing when each is appropriate avoids hard-to-spot bugs:
What Happens When getBean() Is Called
For a singleton bean (the default scope), Spring returns the same fully-initialised instance every time. There is no performance cost to calling getBean() repeatedly — it is a simple map lookup after the first initialisation:
For a prototype bean, Spring creates a fresh instance on every call to getBean(). That instance is never cached and its lifecycle is not managed after creation — you are responsible for calling any cleanup logic yourself.
getBean() are application entry points (like main()), framework bootstrap code, and tests.
Listing and Inspecting Beans
ApplicationContext provides several introspection methods that are valuable in debugging and tooling:
You can also check whether a bean has been initialised yet or query its type without triggering initialisation using ctx.getType("beanName"). These are powerful tools during debugging — put them in a temporary CommandLineRunner in a Spring Boot app to inspect the live context.
A Realistic Worked Example
Here is a compact but realistic setup — a command-line tool that processes orders — demonstrating how booting, retrieval, and close interact:
Notice that main() calls getBean() exactly once — just to get the root service. Everything else flows through constructor injection. This is the correct pattern.
Using ClassPathXmlApplicationContext (Legacy Reading)
If you inherit a pre-Spring-3 codebase or need to consume a legacy XML config file, the boot code looks almost identical:
The XML file lives on the classpath (e.g., src/main/resources/applicationContext.xml). The API for retrieving beans is identical — only the bootstrap line changes. When modernising such a project, your first step is usually replacing this line with AnnotationConfigApplicationContext after migrating beans to @Configuration classes.
Summary
The ApplicationContext is the container you interact with every day, even if Spring Boot usually hides it behind SpringApplication.run(). Know that AnnotationConfigApplicationContext is your default for non-Boot, annotation-driven apps; that you retrieve beans primarily by type; and that direct getBean() calls belong only at the outermost entry point. The next lessons build on this foundation by examining naming, qualifiers, and how to handle multiple beans of the same type.