/*
 * Copyright 2012-2020 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.boot.builder;

import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;

import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.boot.ApplicationContextFactory;
import org.springframework.boot.Banner;
import org.springframework.boot.BootstrapRegistry;
import org.springframework.boot.Bootstrapper;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.convert.ApplicationConversionService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ApplicationListener;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.metrics.ApplicationStartup;
import org.springframework.util.StringUtils;

Builder for SpringApplication and ApplicationContext instances with convenient fluent API and context hierarchy support. Simple example of a context hierarchy:
new SpringApplicationBuilder(ParentConfig.class).child(ChildConfig.class).run(args);
Another common use case is setting active profiles and default properties to set up the environment for an application:
new SpringApplicationBuilder(Application.class).profiles("server")
		.properties("transport=local").run(args);

If your needs are simpler, consider using the static convenience methods in SpringApplication instead.

Author:Dave Syer, Andy Wilkinson
See Also:
Since:1.0.0
/** * Builder for {@link SpringApplication} and {@link ApplicationContext} instances with * convenient fluent API and context hierarchy support. Simple example of a context * hierarchy: * * <pre class="code"> * new SpringApplicationBuilder(ParentConfig.class).child(ChildConfig.class).run(args); * </pre> * * Another common use case is setting active profiles and default properties to set up the * environment for an application: * * <pre class="code"> * new SpringApplicationBuilder(Application.class).profiles(&quot;server&quot;) * .properties(&quot;transport=local&quot;).run(args); * </pre> * * <p> * If your needs are simpler, consider using the static convenience methods in * SpringApplication instead. * * @author Dave Syer * @author Andy Wilkinson * @since 1.0.0 * @see SpringApplication */
public class SpringApplicationBuilder { private final SpringApplication application; private ConfigurableApplicationContext context; private SpringApplicationBuilder parent; private final AtomicBoolean running = new AtomicBoolean(); private final Set<Class<?>> sources = new LinkedHashSet<>(); private final Map<String, Object> defaultProperties = new LinkedHashMap<>(); private ConfigurableEnvironment environment; private Set<String> additionalProfiles = new LinkedHashSet<>(); private boolean registerShutdownHookApplied; private boolean configuredAsChild = false; public SpringApplicationBuilder(Class<?>... sources) { this.application = createSpringApplication(sources); }
Creates a new SpringApplication instances from the given sources. Subclasses may override in order to provide a custom subclass of SpringApplication
Params:
  • sources – the sources
Returns:the SpringApplication instance
Since:1.1.0
/** * Creates a new {@link org.springframework.boot.SpringApplication} instances from the * given sources. Subclasses may override in order to provide a custom subclass of * {@link org.springframework.boot.SpringApplication} * @param sources the sources * @return the {@link org.springframework.boot.SpringApplication} instance * @since 1.1.0 */
protected SpringApplication createSpringApplication(Class<?>... sources) { return new SpringApplication(sources); }
Accessor for the current application context.
Returns:the current application context (or null if not yet running)
/** * Accessor for the current application context. * @return the current application context (or null if not yet running) */
public ConfigurableApplicationContext context() { return this.context; }
Accessor for the current application.
Returns:the current application (never null)
/** * Accessor for the current application. * @return the current application (never null) */
public SpringApplication application() { return this.application; }
Create an application context (and its parent if specified) with the command line args provided. The parent is run first with the same arguments if has not yet been started.
Params:
  • args – the command line arguments
Returns:an application context created from the current state
/** * Create an application context (and its parent if specified) with the command line * args provided. The parent is run first with the same arguments if has not yet been * started. * @param args the command line arguments * @return an application context created from the current state */
public ConfigurableApplicationContext run(String... args) { if (this.running.get()) { // If already created we just return the existing context return this.context; } configureAsChildIfNecessary(args); if (this.running.compareAndSet(false, true)) { synchronized (this.running) { // If not already running copy the sources over and then run. this.context = build().run(args); } } return this.context; } private void configureAsChildIfNecessary(String... args) { if (this.parent != null && !this.configuredAsChild) { this.configuredAsChild = true; if (!this.registerShutdownHookApplied) { this.application.setRegisterShutdownHook(false); } initializers(new ParentContextApplicationContextInitializer(this.parent.run(args))); } }
Returns a fully configured SpringApplication that is ready to run.
Returns:the fully configured SpringApplication.
/** * Returns a fully configured {@link SpringApplication} that is ready to run. * @return the fully configured {@link SpringApplication}. */
public SpringApplication build() { return build(new String[0]); }
Returns a fully configured SpringApplication that is ready to run. Any parent that has been configured will be run with the given args.
Params:
  • args – the parent's args
Returns:the fully configured SpringApplication.
/** * Returns a fully configured {@link SpringApplication} that is ready to run. Any * parent that has been configured will be run with the given {@code args}. * @param args the parent's args * @return the fully configured {@link SpringApplication}. */
public SpringApplication build(String... args) { configureAsChildIfNecessary(args); this.application.addPrimarySources(this.sources); return this.application; }
Create a child application with the provided sources. Default args and environment are copied down into the child, but everything else is a clean sheet.
Params:
  • sources – the sources for the application (Spring configuration)
Returns:the child application builder
/** * Create a child application with the provided sources. Default args and environment * are copied down into the child, but everything else is a clean sheet. * @param sources the sources for the application (Spring configuration) * @return the child application builder */
public SpringApplicationBuilder child(Class<?>... sources) { SpringApplicationBuilder child = new SpringApplicationBuilder(); child.sources(sources); // Copy environment stuff from parent to child child.properties(this.defaultProperties).environment(this.environment) .additionalProfiles(this.additionalProfiles); child.parent = this; // It's not possible if embedded web server are enabled to support web contexts as // parents because the servlets cannot be initialized at the right point in // lifecycle. web(WebApplicationType.NONE); // Probably not interested in multiple banners bannerMode(Banner.Mode.OFF); // Make sure sources get copied over this.application.addPrimarySources(this.sources); return child; }
Add a parent application with the provided sources. Default args and environment are copied up into the parent, but everything else is a clean sheet.
Params:
  • sources – the sources for the application (Spring configuration)
Returns:the parent builder
/** * Add a parent application with the provided sources. Default args and environment * are copied up into the parent, but everything else is a clean sheet. * @param sources the sources for the application (Spring configuration) * @return the parent builder */
public SpringApplicationBuilder parent(Class<?>... sources) { if (this.parent == null) { this.parent = new SpringApplicationBuilder(sources).web(WebApplicationType.NONE) .properties(this.defaultProperties).environment(this.environment); } else { this.parent.sources(sources); } return this.parent; } private SpringApplicationBuilder runAndExtractParent(String... args) { if (this.context == null) { run(args); } if (this.parent != null) { return this.parent; } throw new IllegalStateException( "No parent defined yet (please use the other overloaded parent methods to set one)"); }
Add an already running parent context to an existing application.
Params:
  • parent – the parent context
Returns:the current builder (not the parent)
/** * Add an already running parent context to an existing application. * @param parent the parent context * @return the current builder (not the parent) */
public SpringApplicationBuilder parent(ConfigurableApplicationContext parent) { this.parent = new SpringApplicationBuilder(); this.parent.context = parent; this.parent.running.set(true); return this; }
Create a sibling application (one with the same parent). A side effect of calling this method is that the current application (and its parent) are started without any arguments if they are not already running. To supply arguments when starting the current application and its parent use sibling(Class<?>[], String...) instead.
Params:
  • sources – the sources for the application (Spring configuration)
Returns:the new sibling builder
/** * Create a sibling application (one with the same parent). A side effect of calling * this method is that the current application (and its parent) are started without * any arguments if they are not already running. To supply arguments when starting * the current application and its parent use {@link #sibling(Class[], String...)} * instead. * @param sources the sources for the application (Spring configuration) * @return the new sibling builder */
public SpringApplicationBuilder sibling(Class<?>... sources) { return runAndExtractParent().child(sources); }
Create a sibling application (one with the same parent). A side effect of calling this method is that the current application (and its parent) are started if they are not already running.
Params:
  • sources – the sources for the application (Spring configuration)
  • args – the command line arguments to use when starting the current app and its parent
Returns:the new sibling builder
/** * Create a sibling application (one with the same parent). A side effect of calling * this method is that the current application (and its parent) are started if they * are not already running. * @param sources the sources for the application (Spring configuration) * @param args the command line arguments to use when starting the current app and its * parent * @return the new sibling builder */
public SpringApplicationBuilder sibling(Class<?>[] sources, String... args) { return runAndExtractParent(args).child(sources); }
Explicitly set the context class to be used.
Params:
  • cls – the context class to use
Returns:the current builder
Deprecated:since 2.4.0 in favor of contextFactory(ApplicationContextFactory)
/** * Explicitly set the context class to be used. * @param cls the context class to use * @return the current builder * @deprecated since 2.4.0 in favor of * {@link #contextFactory(ApplicationContextFactory)} */
@Deprecated public SpringApplicationBuilder contextClass(Class<? extends ConfigurableApplicationContext> cls) { this.application.setApplicationContextClass(cls); return this; }
Explicitly set the factory used to create the application context.
Params:
  • factory – the factory to use
Returns:the current builder
Since:2.4.0
/** * Explicitly set the factory used to create the application context. * @param factory the factory to use * @return the current builder * @since 2.4.0 */
public SpringApplicationBuilder contextFactory(ApplicationContextFactory factory) { this.application.setApplicationContextFactory(factory); return this; }
Add more sources (configuration classes and components) to this application.
Params:
  • sources – the sources to add
Returns:the current builder
/** * Add more sources (configuration classes and components) to this application. * @param sources the sources to add * @return the current builder */
public SpringApplicationBuilder sources(Class<?>... sources) { this.sources.addAll(new LinkedHashSet<>(Arrays.asList(sources))); return this; }
Flag to explicitly request a specific type of web application. Auto-detected based on the classpath if not set.
Params:
  • webApplicationType – the type of web application
Returns:the current builder
Since:2.0.0
/** * Flag to explicitly request a specific type of web application. Auto-detected based * on the classpath if not set. * @param webApplicationType the type of web application * @return the current builder * @since 2.0.0 */
public SpringApplicationBuilder web(WebApplicationType webApplicationType) { this.application.setWebApplicationType(webApplicationType); return this; }
Flag to indicate the startup information should be logged.
Params:
  • logStartupInfo – the flag to set. Default true.
Returns:the current builder
/** * Flag to indicate the startup information should be logged. * @param logStartupInfo the flag to set. Default true. * @return the current builder */
public SpringApplicationBuilder logStartupInfo(boolean logStartupInfo) { this.application.setLogStartupInfo(logStartupInfo); return this; }
Sets the Banner instance which will be used to print the banner when no static banner file is provided.
Params:
  • banner – the banner to use
Returns:the current builder
/** * Sets the {@link Banner} instance which will be used to print the banner when no * static banner file is provided. * @param banner the banner to use * @return the current builder */
public SpringApplicationBuilder banner(Banner banner) { this.application.setBanner(banner); return this; } public SpringApplicationBuilder bannerMode(Banner.Mode bannerMode) { this.application.setBannerMode(bannerMode); return this; }
Sets if the application is headless and should not instantiate AWT. Defaults to true to prevent java icons appearing.
Params:
  • headless – if the application is headless
Returns:the current builder
/** * Sets if the application is headless and should not instantiate AWT. Defaults to * {@code true} to prevent java icons appearing. * @param headless if the application is headless * @return the current builder */
public SpringApplicationBuilder headless(boolean headless) { this.application.setHeadless(headless); return this; }
Sets if the created ApplicationContext should have a shutdown hook registered.
Params:
  • registerShutdownHook – if the shutdown hook should be registered
Returns:the current builder
/** * Sets if the created {@link ApplicationContext} should have a shutdown hook * registered. * @param registerShutdownHook if the shutdown hook should be registered * @return the current builder */
public SpringApplicationBuilder registerShutdownHook(boolean registerShutdownHook) { this.registerShutdownHookApplied = true; this.application.setRegisterShutdownHook(registerShutdownHook); return this; }
Fixes the main application class that is used to anchor the startup messages.
Params:
  • mainApplicationClass – the class to use.
Returns:the current builder
/** * Fixes the main application class that is used to anchor the startup messages. * @param mainApplicationClass the class to use. * @return the current builder */
public SpringApplicationBuilder main(Class<?> mainApplicationClass) { this.application.setMainApplicationClass(mainApplicationClass); return this; }
Flag to indicate that command line arguments should be added to the environment.
Params:
  • addCommandLineProperties – the flag to set. Default true.
Returns:the current builder
/** * Flag to indicate that command line arguments should be added to the environment. * @param addCommandLineProperties the flag to set. Default true. * @return the current builder */
public SpringApplicationBuilder addCommandLineProperties(boolean addCommandLineProperties) { this.application.setAddCommandLineProperties(addCommandLineProperties); return this; }
Flag to indicate if the ApplicationConversionService should be added to the application context's Environment.
Params:
  • addConversionService – if the conversion service should be added.
Returns:the current builder
Since:2.1.0
/** * Flag to indicate if the {@link ApplicationConversionService} should be added to the * application context's {@link Environment}. * @param addConversionService if the conversion service should be added. * @return the current builder * @since 2.1.0 */
public SpringApplicationBuilder setAddConversionService(boolean addConversionService) { this.application.setAddConversionService(addConversionService); return this; }
Adds a Bootstrapper that can be used to initialize the BootstrapRegistry.
Params:
  • bootstrapper – the bootstraper
Returns:the current builder
Since:2.4.0
/** * Adds a {@link Bootstrapper} that can be used to initialize the * {@link BootstrapRegistry}. * @param bootstrapper the bootstraper * @return the current builder * @since 2.4.0 */
public SpringApplicationBuilder addBootstrapper(Bootstrapper bootstrapper) { this.application.addBootstrapper(bootstrapper); return this; }
Flag to control whether the application should be initialized lazily.
Params:
  • lazyInitialization – the flag to set. Defaults to false.
Returns:the current builder
Since:2.2
/** * Flag to control whether the application should be initialized lazily. * @param lazyInitialization the flag to set. Defaults to false. * @return the current builder * @since 2.2 */
public SpringApplicationBuilder lazyInitialization(boolean lazyInitialization) { this.application.setLazyInitialization(lazyInitialization); return this; }
Default properties for the environment in the form key=value or key:value. Multiple calls to this method are cumulative and will not clear any previously set properties.
Params:
  • defaultProperties – the properties to set.
See Also:
Returns:the current builder
/** * Default properties for the environment in the form {@code key=value} or * {@code key:value}. Multiple calls to this method are cumulative and will not clear * any previously set properties. * @param defaultProperties the properties to set. * @return the current builder * @see SpringApplicationBuilder#properties(Properties) * @see SpringApplicationBuilder#properties(Map) */
public SpringApplicationBuilder properties(String... defaultProperties) { return properties(getMapFromKeyValuePairs(defaultProperties)); } private Map<String, Object> getMapFromKeyValuePairs(String[] properties) { Map<String, Object> map = new HashMap<>(); for (String property : properties) { int index = lowestIndexOf(property, ":", "="); String key = (index > 0) ? property.substring(0, index) : property; String value = (index > 0) ? property.substring(index + 1) : ""; map.put(key, value); } return map; } private int lowestIndexOf(String property, String... candidates) { int index = -1; for (String candidate : candidates) { int candidateIndex = property.indexOf(candidate); if (candidateIndex > 0) { index = (index != -1) ? Math.min(index, candidateIndex) : candidateIndex; } } return index; }
Default properties for the environment.Multiple calls to this method are cumulative and will not clear any previously set properties.
Params:
  • defaultProperties – the properties to set.
See Also:
Returns:the current builder
/** * Default properties for the environment.Multiple calls to this method are cumulative * and will not clear any previously set properties. * @param defaultProperties the properties to set. * @return the current builder * @see SpringApplicationBuilder#properties(String...) * @see SpringApplicationBuilder#properties(Map) */
public SpringApplicationBuilder properties(Properties defaultProperties) { return properties(getMapFromProperties(defaultProperties)); } private Map<String, Object> getMapFromProperties(Properties properties) { Map<String, Object> map = new HashMap<>(); for (Object key : Collections.list(properties.propertyNames())) { map.put((String) key, properties.get(key)); } return map; }
Default properties for the environment. Multiple calls to this method are cumulative and will not clear any previously set properties.
Params:
  • defaults – the default properties
See Also:
Returns:the current builder
/** * Default properties for the environment. Multiple calls to this method are * cumulative and will not clear any previously set properties. * @param defaults the default properties * @return the current builder * @see SpringApplicationBuilder#properties(String...) * @see SpringApplicationBuilder#properties(Properties) */
public SpringApplicationBuilder properties(Map<String, Object> defaults) { this.defaultProperties.putAll(defaults); this.application.setDefaultProperties(this.defaultProperties); if (this.parent != null) { this.parent.properties(this.defaultProperties); this.parent.environment(this.environment); } return this; }
Add to the active Spring profiles for this app (and its parent and children).
Params:
  • profiles – the profiles to add.
Returns:the current builder
/** * Add to the active Spring profiles for this app (and its parent and children). * @param profiles the profiles to add. * @return the current builder */
public SpringApplicationBuilder profiles(String... profiles) { this.additionalProfiles.addAll(Arrays.asList(profiles)); this.application.setAdditionalProfiles(StringUtils.toStringArray(this.additionalProfiles)); return this; } private SpringApplicationBuilder additionalProfiles(Collection<String> additionalProfiles) { this.additionalProfiles = new LinkedHashSet<>(additionalProfiles); this.application.setAdditionalProfiles(StringUtils.toStringArray(this.additionalProfiles)); return this; }
Bean name generator for automatically generated bean names in the application context.
Params:
  • beanNameGenerator – the generator to set.
Returns:the current builder
/** * Bean name generator for automatically generated bean names in the application * context. * @param beanNameGenerator the generator to set. * @return the current builder */
public SpringApplicationBuilder beanNameGenerator(BeanNameGenerator beanNameGenerator) { this.application.setBeanNameGenerator(beanNameGenerator); return this; }
Environment for the application context.
Params:
  • environment – the environment to set.
Returns:the current builder
/** * Environment for the application context. * @param environment the environment to set. * @return the current builder */
public SpringApplicationBuilder environment(ConfigurableEnvironment environment) { this.application.setEnvironment(environment); this.environment = environment; return this; }
ResourceLoader for the application context. If a custom class loader is needed, this is where it would be added.
Params:
  • resourceLoader – the resource loader to set.
Returns:the current builder
/** * {@link ResourceLoader} for the application context. If a custom class loader is * needed, this is where it would be added. * @param resourceLoader the resource loader to set. * @return the current builder */
public SpringApplicationBuilder resourceLoader(ResourceLoader resourceLoader) { this.application.setResourceLoader(resourceLoader); return this; }
Add some initializers to the application (applied to the ApplicationContext before any bean definitions are loaded).
Params:
  • initializers – some initializers to add
Returns:the current builder
/** * Add some initializers to the application (applied to the {@link ApplicationContext} * before any bean definitions are loaded). * @param initializers some initializers to add * @return the current builder */
public SpringApplicationBuilder initializers(ApplicationContextInitializer<?>... initializers) { this.application.addInitializers(initializers); return this; }
Add some listeners to the application (listening for SpringApplication events as well as regular Spring events once the context is running). Any listeners that are also ApplicationContextInitializer will be added to the initializers automatically.
Params:
  • listeners – some listeners to add
Returns:the current builder
/** * Add some listeners to the application (listening for SpringApplication events as * well as regular Spring events once the context is running). Any listeners that are * also {@link ApplicationContextInitializer} will be added to the * {@link #initializers(ApplicationContextInitializer...) initializers} automatically. * @param listeners some listeners to add * @return the current builder */
public SpringApplicationBuilder listeners(ApplicationListener<?>... listeners) { this.application.addListeners(listeners); return this; }
Configure the ApplicationStartup to be used with the ApplicationContext for collecting startup metrics.
Params:
  • applicationStartup – the application startup to use
Returns:the current builder
Since:2.4.0
/** * Configure the {@link ApplicationStartup} to be used with the * {@link ApplicationContext} for collecting startup metrics. * @param applicationStartup the application startup to use * @return the current builder * @since 2.4.0 */
public SpringApplicationBuilder applicationStartup(ApplicationStartup applicationStartup) { this.application.setApplicationStartup(applicationStartup); return this; } }