Dumping the Spring Environment in Spring Boot

When developing Spring Boot applications, I often need to check if property values are correctly received from configuration files, environment variables, or other sources. There are various ways to perform this task. This article will present my solution for dumping the Spring Environment using a simple application listener.


If you need to check the Spring Environment, one possible solution is Spring Boot Actuator. However, this approach may not be suitable for several reasons. First, not all Spring Boot applications have or need to have Actuator. Second, the Spring application context may fail to start; in this case, Actuator will not help you since the application is not running.

Another solution is dumping (using logging) the entire Spring Environment at a very early stage of the Spring application. This is the solution described in this article.

The Environment and ConfigurableEnvironment interfaces

In Spring, the “Environment” models two different aspects of every application: profiles and properties. Properties come from various sources, like system properties, environment variables, and configuration files.

The Environment is represented at the highest level by the Environment interface, which is an extension of PropertyResolver. Environment has only one direct sub-interface, ConfigurableEnvironment. This latter interface can manipulate profiles and properties in various ways.

In Spring Boot applications, the concrete environment object is typically always an implementation of ConfigurableEnvironment. This interface is essential because it provides the getPropertySources() method, which returns a MutablePropertySources object described in the following section.

The MutablePropertySources and PropertySource classes

MutablePropertySources is the default implementation of the PropertySources interface and acts as a container for a sequence of PropertySource objects. This characteristic is easy to spot because MutablePropertySources also implements Iterable<PropertySource<?>>, so you can iterate on property sources.

Each PropertySource object represents a single source of properties, like the environment variables or the application.properties/.yaml file. There is, however, an important aspect to know about PropertySource. It allows you to look up a property value by name but doesn’t offer any method to iterate on property names.

Fortunately, PropertySource has a sub-class named EnumerablePropertySource. It provides the getPropertyNames() method, so you can get an array of all property names available in a PropertySource object.

In real Spring Boot applications, some property sources are enumerable while others are not. You will typically find that the most helpful property sources are enumerable while a few others are not. Thus, as described in this article, dumping the entire Spring Environment is possible and very valuable.

The solution code

After the theoretical part, it’s time to see my personal solution. The class I will show is an implementation of ApplicationListener, which is the Spring interface used to receive events from the application context. This is an application of the well-known “Observer” design pattern.

I have chosen to handle the event named ApplicationEnvironmentPreparedEvent. Note that this is a Spring Boot-specific event; thus, you cannot use it in a “pure” Spring Framework application. This event is fired very early in a Spring Boot application life since it happens just after the Environment is available but before the Spring context is created.

Since the context is not yet available at this stage, we cannot simply use @Component to make the class a Spring “bean”. This listener must be registered using the SpringApplication class or, more generally, using the META-INF/spring.factories file (described later).

The following is my solution code.

package your.pkgname;

import java.util.Arrays;
import java.util.Objects;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.EnumerablePropertySource;
import org.springframework.core.env.PropertyResolver;
import org.springframework.core.env.PropertySource;

public class SpringEnvDumper implements ApplicationListener<ApplicationEnvironmentPreparedEvent> {
    private static final Logger logger = LoggerFactory.getLogger(SpringEnvDumper.class);

    public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {
        if (logger.isDebugEnabled()) {

    private static void dumpEnvironment(ConfigurableEnvironment environment) {
        logger.debug("======== SPRING ENVIRONMENT DUMP ========");

        for (PropertySource<?> source : environment.getPropertySources()) {
            dumpPropertySource(environment, source);


    private static void dumpPropertySource(PropertyResolver resolver, PropertySource<?> source) {
        logger.debug("PropertySource: \"{}\"", source.getName());

        if (!(source instanceof EnumerablePropertySource)) {
            logger.debug("   <not an EnumerablePropertySource>");

        EnumerablePropertySource<?> enumerableSource = (EnumerablePropertySource<?>) source;
        String[] propNames = enumerableSource.getPropertyNames();

        if (propNames.length == 0) {
            logger.debug("   <no properties>");


        for (String propName : propNames) {
            Object propValue = enumerableSource.getProperty(propName);
            dumpProperty(resolver, propName, propValue);

    private static void dumpProperty(PropertyResolver resolver, String propName, Object propValue) {
        logger.debug("   \"{}\" = {}", propName, valueAsString(propValue));

        if (propValue instanceof String) {
            String propValueResolved = resolver.resolvePlaceholders((String) propValue);

            if (!Objects.equals(propValueResolved, propValue)) {
                logger.debug("      `---> {}", valueAsString(propValueResolved));

    private static String valueAsString(Object value) {
        if (value instanceof String) {
            return "\"" + value + "\"";

        return String.valueOf(value);

Registering the listener

As anticipated, the SpringEnvDumper class, which implements the listener, must be explicitly registered. The most simple and general way to do this is by using the spring.factories file. In a Maven or Gradle project, this file is usually located under the path:


So, create the spring.factories file with the following content:

org.springframework.context.ApplicationListener = your.pkgname.SpringEnvDumper

(note: replace your.pkgname with your real package name!)

Sample output

Suppose that you also have the following application.yaml (or .properties equivalent) configuration file:

  port: ${SVRPORT:8080}
    your.pkgname: DEBUG

If everything works correctly, you should see a logging output that is similar to this:

  ………  your.pkgname.SpringEnvDumper        : ======== SPRING ENVIRONMENT DUMP ========
  ………  your.pkgname.SpringEnvDumper        : PropertySource: "configurationProperties"
  ………  your.pkgname.SpringEnvDumper        :    <not an EnumerablePropertySource>
  ………  your.pkgname.SpringEnvDumper        : PropertySource: "servletConfigInitParams"
  ………  your.pkgname.SpringEnvDumper        :    <not an EnumerablePropertySource>
  ………  your.pkgname.SpringEnvDumper        : PropertySource: "servletContextInitParams"
  ………  your.pkgname.SpringEnvDumper        :    <not an EnumerablePropertySource>
  ………  your.pkgname.SpringEnvDumper        : PropertySource: "systemProperties"
  ………  your.pkgname.SpringEnvDumper        :    "file.encoding" = "UTF-8"
  ………  your.pkgname.SpringEnvDumper        :    "file.separator" = "\"
  ………  your.pkgname.SpringEnvDumper        :    "java.awt.headless" = "true"
  ………                     ⁞                              ⁞    ⁞
  ………                     ⁞                              ⁞    ⁞
  ………  your.pkgname.SpringEnvDumper        :    "user.script" = ""
  ………  your.pkgname.SpringEnvDumper        :    "user.timezone" = "Europe/Rome"
  ………  your.pkgname.SpringEnvDumper        :    "user.variant" = ""
  ………  your.pkgname.SpringEnvDumper        : PropertySource: "systemEnvironment"
  ………                     ⁞                              ⁞    ⁞
  ………  your.pkgname.SpringEnvDumper        :    "COMPUTERNAME" = "MYPC"
  ………                     ⁞                              ⁞    ⁞
  ………  your.pkgname.SpringEnvDumper        :    "DIRCMD" = "/OGN"
  ………                     ⁞                              ⁞    ⁞
  ………  your.pkgname.SpringEnvDumper        : PropertySource: "random"
  ………  your.pkgname.SpringEnvDumper        :    <not an EnumerablePropertySource>
  ………  your.pkgname.SpringEnvDumper        : PropertySource: "Config resource 'class path resource [application.yaml]' via location 'optional:classpath:/'"
  ………  your.pkgname.SpringEnvDumper        :    "logging.level.your.pkgname" = "DEBUG"
  ………  your.pkgname.SpringEnvDumper        :    "server.port" = "${SVRPORT:8080}"
  ………  your.pkgname.SpringEnvDumper        :       `---> "8080"
  ………  your.pkgname.SpringEnvDumper        : =========================================

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 :: Spring Boot ::                (v3.1.2)


Note that the Spring Environment dumping happens before the text banner’s output!

Final notes

Before I wrap up, I’d like to provide some notes about the code.

First of all, I used SLF4J for logging. You are free to use any other logging library or “facade” logging library. Secondly, I logged all events at DEBUG level. Again, you are free to change the level to whatever you want.

In particular, you should notice the part of the code that checks if a property source is enumerable:

        if (!(source instanceof EnumerablePropertySource)) {
            logger.debug("   <not an EnumerablePropertySource>");

If the property source object is not of type EnumerablePropertySource, there is no straightforward way to get all the property names.

Similar Posts