How to start a container in Spring Boot

The Spring container (or just container) is where the objects it manages (Spring-managed beans) live. The container creates and manage the Spring-managed beans and configure and resolve dependencies between components. In this article, we’re going to see three ways of initializing the Spring container.

Creating and configuring the project

1 – Open Spring Initializr. We’re going to create a Java 21, Gradle project with the newest version of Spring Boot; there’s no need to add dependencies.

2 – Open the project in IntelliJ IDEA (Community Edition or Ultimate).

First method: the ContainerApplication class

Spring Initializr has already created for you a class named ContainerApplication with a main(…) method. Inside the main(…) method there’s a run(…) method, which starts up the container.

@SpringBootApplication
public class ContainerApplication {

	public static void main(String[] args) {
		SpringApplication.run(ContainerApplication.class, args);
	}

}

Notice that run(…) is a static method that has two parameters: the first one is the initial configuration, which here is the type of our own class; and the second one is the args passed to the main method. Spring uses these arguments to configure the container. It’s important to note that if there is an error in the configuration, the container isn’t started and run(…) throws an exception; however, if the configuration is fine, the container will initialize all components and finish (run(…) will exit).

Besides the static method run(…), there are two other ways to start the container. These options have the advantage to allow us to configure the container right at the start. Let’s see them.

Second method: Instantiating SpringApplication

One alternative to run(…) method is to create a SpringApplication object and later use its run(…) instance method. This option allows us to make some settings in the SpringApplication object:

@SpringBootApplication
public class ContainerApplication {

	public static void main(String[] args) {
		SpringApplication app = new SpringApplication(ContainerApplication.class);
		app.setBannerMode(Banner.Mode.OFF);
		app.setLogStartupInfo(false);
		app.run(args);
	}

}

In the example above we set two settings: first we turned off the start banner (it’s also possible to do that via configuration property, just add spring.main.banner-mode=off in the application.properties or application.yml); besides the banner, other startup information is output by default, like the active profiles; we can switch off these outputs with setLogStartupInfo(false).

Third method: SpringApplicationBuilder

The other alternative to the static run(…) method is the class SpringApplicationBuilder, which uses the builder pattern to create a SpringApplication.

@SpringBootApplication
public class ContainerApplication {

	public static void main(String[] args) {
		ConfigurableApplicationContext ctx = new SpringApplicationBuilder(ContainerApplication.class)
				.bannerMode(Banner.Mode.OFF)
				.logStartupInfo(false)
				.run(args);
	}

}

With this option, you can easily cascade methods for setting.

Notice that the run(…) method, whether it’s from SpringApplication or SpringApplicationBuilder, returns an application context (or just context). This context can be stored in a variable of type ConfigurableApplicationContext, which is an interface.

Printing the components from the container

With the following snippet we can print the list of beans created and managed by the container:

@SpringBootApplication
public class ContainerApplication {

	public static void main(String[] args) {
		ApplicationContext ctx = SpringApplication.run(ContainerApplication.class, args);
		Arrays.stream(ctx.getBeanDefinitionNames())
				.sorted()
				.forEach(System.out::println);
	}

}

Notice that, although the return type of run(…) isConfigurableApplicationContext, we can use ApplicationContext instead because it’s shorter and it also extends ListableBeanFactory, which is the type that contains the method getBeanDefinitionNames().

After running the program, a list of all Spring-managed beans appears on the the console.

applicationAvailability
applicationTaskExecutor
applicationTaskExecutorAsyncConfigurer
bootstrapExecutorAliasPostProcessor
containerApplication
fileWatcher
forceAutoProxyCreatorToUseClassProxying
lifecycleProcessor
org.springframework.aop.config.internalAutoProxyCreator
org.springframework.boot.autoconfigure.AutoConfigurationPackages
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration$ClassProxyingConfiguration
org.springframework.boot.autoconfigure.availability.ApplicationAvailabilityAutoConfiguration
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration
org.springframework.boot.autoconfigure.context.LifecycleAutoConfiguration
org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration
org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration
org.springframework.boot.autoconfigure.internalCachingMetadataReaderFactory
org.springframework.boot.autoconfigure.sql.init.SqlInitializationAutoConfiguration
org.springframework.boot.autoconfigure.ssl.SslAutoConfiguration
org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration
org.springframework.boot.autoconfigure.task.TaskExecutorConfigurations$AsyncConfigurerConfiguration
org.springframework.boot.autoconfigure.task.TaskExecutorConfigurations$BootstrapExecutorConfiguration
org.springframework.boot.autoconfigure.task.TaskExecutorConfigurations$SimpleAsyncTaskExecutorBuilderConfiguration
org.springframework.boot.autoconfigure.task.TaskExecutorConfigurations$TaskExecutorConfiguration
org.springframework.boot.autoconfigure.task.TaskExecutorConfigurations$ThreadPoolTaskExecutorBuilderConfiguration
org.springframework.boot.autoconfigure.task.TaskSchedulingAutoConfiguration
org.springframework.boot.autoconfigure.task.TaskSchedulingConfigurations$SimpleAsyncTaskSchedulerBuilderConfiguration
org.springframework.boot.autoconfigure.task.TaskSchedulingConfigurations$ThreadPoolTaskSchedulerBuilderConfiguration
org.springframework.boot.context.internalConfigurationPropertiesBinder
org.springframework.boot.context.properties.BoundConfigurationProperties
org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor
org.springframework.boot.context.properties.EnableConfigurationPropertiesRegistrar.methodValidationExcludeFilter
org.springframework.boot.sql.init.dependency.DatabaseInitializationDependencyConfigurer$DependsOnDatabaseInitializationPostProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.event.internalEventListenerFactory
org.springframework.context.event.internalEventListenerProcessor
propertySourcesPlaceholderConfigurer
simpleAsyncTaskExecutorBuilder
simpleAsyncTaskSchedulerBuilder
spring.info-org.springframework.boot.autoconfigure.info.ProjectInfoProperties
spring.lifecycle-org.springframework.boot.autoconfigure.context.LifecycleProperties
spring.sql.init-org.springframework.boot.autoconfigure.sql.init.SqlInitializationProperties
spring.ssl-org.springframework.boot.autoconfigure.ssl.SslProperties
spring.task.execution-org.springframework.boot.autoconfigure.task.TaskExecutionProperties
spring.task.scheduling-org.springframework.boot.autoconfigure.task.TaskSchedulingProperties
sslBundleRegistry
sslPropertiesSslBundleRegistrar
threadPoolTaskExecutorBuilder
threadPoolTaskSchedulerBuilder

These components are created without us having to do anything thanks to Spring Boot’s auto-configuration. Notice in the list above that our own configuration, containerApplication, was created and placed in the container; this component is automatically named, starting with lowercase.

Getting a bean by its name

The interfaces ConfigurableApplicationContext and ApplicationContext extend BeanFactory, which has methods for taking Spring-managed beans from the context.

boolean containsBean(String name)
T getBean(Class<T> requiredType)
Object getBean(String name)
T getBean(String name, Class<T> requiredType)

Let’s exemplify the use of getBean(Class<T> requiredType):

@SpringBootApplication
public class ContainerApplication {

	public static void main(String[] args) {
		ApplicationContext ctx = SpringApplication.run(ContainerApplication.class, args);
		MyBean bean = ctx.getBean(MyBean.class);
	}

}

The return of those methods is a bean or, if Spring can’t find it, an exception is thrown.

All beans have a name. Methods like getBean(String name, Class<T> requiredType) query the bean by it’s name:

@SpringBootApplication
public class ContainerApplication {

	public static void main(String[] args) {
		ApplicationContext ctx = SpringApplication.run(ContainerApplication.class, args);
		ContainerApplication bean = ctx.getBean("containerApplication", ContainerApplication.class);
	}

}

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top