This lesson will introduce you to the previously-mentioned Spring Application Context (ApplicationContext), a cornerstone of the Spring framework.
The Application Context is often called the "container", the "bean factory", or the "bucket of beans" - ok we coined that one, but you get the idea! It's responsible for managing the beans for your application.
But how do you go about ensuring these beans are created and available? Read on to find out.
What is the Spring ApplicationContext?
In Spring, the ApplicationContext is a central interface that provides configuration for a Spring application. It represents the Spring IoC container and is responsible for instantiating, configuring, auto-wiring, and destroying the beans. Remember, a "bean" is any Java object that is being managed by the Spring IoC container.
Hence, the ApplicationContext is often referred to and/or compared to a "Bean Factory". As you are learning, Spring will be "injecting" beans (aka "objects") into your classes when needed, and it is the ApplicationContext that manages and provides these beans.
The IoC container receives instructions on what objects to instantiate, configure, autowire, or destroy by reading configuration metadata which can be provided in the form of Java annotations, Java-based configuration, or XML files (legacy).
At the moment, these topics are being introduced for context to help you better understand what is happening behind the scenes within the Spring Framework. There's a lot on this page, and you may benefit from reading it through a second, even third time, so that the concepts become clearer, as that may not immediately be so. This could be a great page to review with your mentor or a study group - to ensure your grasp of these fundamentals. But, as always, don't worry too much; it becomes clearer with practice.
The ApplicationContext interface:
public interface ApplicationContext extends EnvironmentCapable,
ListableBeanFactory,
HierarchicalBeanFactory,
MessageSource,
ApplicationEventPublisher,
ResourcePatternResolver {
@Nullable
String getId();
String getApplicationName();
String getDisplayName();
long getStartupDate();
@Nullable
ApplicationContext getParent();
AutowireCapableBeanFactory getAutowireCapableBeanFactory()
throws IllegalStateException;
}
What Does the ApplicationContext Provide?
- Bean factory methods for accessing application components. (inherited from ListableBeanFactory interface)
- The ability to access resources, such as URLs and files. (inherited from ResourceLoader interface ).
- The ability to publish events to the registered listeners. (inherited from ApplicationEventPublisher interface)
- The ability to resolve messages and support internationalization. (inherited from MessageSource interface)
- Inheritance from a parent context - if utilizing multiple contexts within a single application.
The Spring ApplicationContext provides all kinds of capabilities - you will be using and becoming very familiar with many of these throughout the course. As you discovered in the previous section, the ApplicationContext also provides you access to design patterns:
-
The IoC pattern, implemented through the ApplicationContext, involves the inversion of the control flow of a program. Instead of the application controlling the flow, the control is inverted, and the framework or container (such as the ApplicationContext) manages the control flow.
-
The DI pattern, facilitated by the ApplicationContext, focuses on injecting dependencies into a class rather than the class creating or managing its dependencies. This promotes loose coupling and enhances the flexibility and testability of the code.
Java Configuration
In the previous section, you created an instance of the ApplicationContext - here it is again:
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class CodingNomadDemo {
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(
CodingNomadConfiguration.class);
CodingNomad codingNomad = ctx.getBean(CodingNomad.class);
System.out.println(codingNomad.createAwesomeSoftware());
}
}
Example Location:com.codingnomads.ioc.lab.initial
To help get a better understanding of the code from the previous lab and what is taking place, let's break things down a bit.
Have a quick look back at the CodingNomadConfiguration class in the example package. Note that the class is annotated with @Configuration, and it defines several methods annotated with @Bean. Each method annotated with @Bean instructs Spring to add a "bean" of that particular type to the ApplicationContext.
So the method annotated with @Bean that returns a Framework - tells Spring to add a Framework instance (bean) to the ApplicationContext. The method body itself tells Spring how to create that particular bean. You see there are methods annotated with @Bean that return an IDE and a JDK - the same rules apply - Spring will add these as beans to the ApplicationContext.
The @ComponentScan annotation as seen with @ComponentScan (basePackages = "com.codingnomads.ioc.lab.initial") directs Spring to search within the specified package for classes annotated with Spring stereotypes such as @Component, thereby registering them as beans in the ApplicationContext. As it scans through the package, it comes across the CodingNomad class - and if you take a quick look at that class - you'll see it's annotated with @Component. This is the magic hint that tells Spring this class, too, is to be instantiated and loaded into the ApplicationContext as an available bean for whenever one is needed.
Lastly, note that the creation of a CodingNomad instance itself requires a JDK, IDE, and Framework - each of these is automatically injected by Spring - as each one of these already by now exists as a bean in the ApplicationContext.
In your code, when you now invoke the ctx.getBean(CodingNomad.class) method, you can get a fully initialized bean from the ApplicationContext.
This is a view into what Spring is doing for you behind the scenes any time you need a bean in a given location. Spring abstracts much of this code away, so generally you don't ever have to manually grab a bean like this, but if you want to, you absolutely can.
XML Configuration
You can also use an XML-based configuration to declare the beans (aka "set them up"). You can use either the FileSystemXmlApplicationContext, or the ClassPathXmlApplicationContext to implement. Time to see that in action.
Inside IntelliJ, navigate to the following XML configuration file:/src/main/resources/xml-config/codingnomad_configuration.xml
<?xml version = "1.0" encoding = "UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.codingnomads.corespring.examples.application_context.xml"/>
<bean id="framework" class="com.codingnomads.corespring.examples.application_context.xml.Framework">
<property name="name" value="Spring Boot"/>
<property name="version" value="3.2"/>
</bean>
<bean id="ide" class="com.codingnomads.corespring.examples.application_context.xml.IDE">
<property name="name" value="IntelliJ IDEA"/>
<property name="version" value="2023.5"/>
</bean>
<bean id="jdk" class="com.codingnomads.corespring.examples.application_context.xml.JDK">
<property name="name" value="OpenJDK"/>
<property name="version" value="17"/>
</bean>
</beans>
This XML configuration essentially conveys the same information as the CodingNomadConfiguration class did previously, albeit in a different format. To integrate this configuration, noteworthy changes have been made to your CodingNomadDemo class:
@SpringBootApplication
public class CodingNomadDemo {
public static void main(String[] args) {
ApplicationContext ctx =
new ClassPathXmlApplicationContext(
"xml-config/codingnomad_configuration.xml");
CodingNomad codingNomad = ctx.getBean(CodingNomad.class);
System.out.println(codingNomad.createAwesomeSoftware());
}
}
In this updated version, the ClassPathXmlApplicationContext is used to instantiate a context based on the content specified in the XML file ("xml-config/codingnomad_configuration.xml"). This approach aligns with the Spring framework's versatility, allowing you to configure your application using either Java annotations or XML, depending on your preferences and project requirements.
Learn by Doing
Package:com.codingnomads.corespring.examples.application_context.xml
- Create a new POJO that represents a tool that might be used by a software developer.
- Inside the XML file referenced above, define a bean for this new class.
- In the CodingNomad class, add a final field for this class, and it will now be injected!
Remember to push your changes to GitHub.
Now, like the IoC lab before, it produces the same output.
Tip: XML is the legacy way of defining beans - you have used the @Bean annotation in previous sections, which is the new and standard way. Learning about this type of XML configuration allows you to recognize and configure legacy code (because there is tons of it out there!)
Summary: Spring ApplicationContext
This lesson explained that the ApplicationContext provides:
- Automatic bean instantiation and lifecycle management.
- The ability to load file resources.
- Bean factory methods for accessing application components.
- The ability to publish events to registered listeners.
- The implementation of IoC and DI design patterns.
Next up, you'll learn how to utilize the event capabilities.