0

For Spring Framework 6 about Profiles, consider two ways to report the profiles active at the same time in the same app

Spring Profiles Report I

public static void reporteProfilesAndBeansDefinitions(ApplicationContext ctx) {
    System.out.println("");
    System.out.println("---------------------------------");
    System.out.println("Reporte Spring ApplicationContext");
    System.out.println("---------------------------------");
    System.out.println("");

    String[] activeProfiles = ctx.getEnvironment().getActiveProfiles();
    System.out.println("Active Profiles: " + activeProfiles.length);
    if(activeProfiles.length > 0) {
        for(String ap : activeProfiles) {
            System.out.println(" " + ap);
        }
    }
    else {
        System.out.println(" -");
    }

}

Spring Profiles Report II

public class SystemPropertiesReportServiceImpl implements SystemPropertiesReportService {

    private final String[] springProfilesActive;
    
    public SystemPropertiesReportServiceImpl(String[] springProfilesActive) {
        this.springProfilesActive = springProfilesActive;
    }

    @Override
    public void reporte() {
        System.out.println("");
        System.out.println("-------------------------------------");
        System.out.println("Reporte Spring SpEL System Properties");
        System.out.println("-------------------------------------");
        System.out.println("");
        System.out.println(" spring.profiles.active: " + arrayToList(springProfilesActive));
        System.out.println("");
    }

    private List<String> arrayToList(String[] profiles) {
        if(profiles != null) {
            return Arrays.asList(profiles);
        }
        else {
            return null;
        }
    }

}

That class is created through:

@Configuration
class AppConfig {

    @Bean
    SystemPropertiesReportService systemPropertiesReportService(
            @Value("#{systemProperties['spring.profiles.active']}") String[] springProfilesActive){
        return new SystemPropertiesReportServiceImpl(springProfilesActive);
    }

}

As a third approach the following too (but consider the two previous for more consideration because they are based on Spring API):

Spring Profiles Report III

public static void reporteProperties() {
    System.out.println("");
    System.out.println("------------------------------");
    System.out.println("Reporte Java System Properties");
    System.out.println("------------------------------");
    System.out.println("");
    System.out.println(" spring.profiles.active: " +
                         System.getProperty("spring.profiles.active"));
    System.out.println("");
}

Now, in the main method exists the following:

 ConfigurableApplicationContext ctx =
                (ConfigurableApplicationContext) SpringFrameworkFactory.createApplicationContext();

 SystemPropertiesReportService systemPropertiesReportService =
                ctx.getBean(SystemPropertiesReportService.class);

 SpringFrameworkUtils.reporteProfilesAndBeansDefinitions(ctx); // approach I
 systemPropertiesReportService.reporte();                      // approach II
 JavaSystemUtils.reporteProperties();                          // approach III    

Now consider the following

Alpha

if createApplicationContext() contains:

public static ApplicationContext createApplicationContext() {
    System.setProperty("spring.profiles.active", "prod,log,info");
    ConfigurableApplicationContext ctx =
            new AnnotationConfigApplicationContext("com.manuel.jordan.config");
    return ctx;
}

Where it is the correct approach because the profiles were defined/declared before to create the Spring ApplicationContext, therefore the output is as follows:

---------------------------------
Reporte Spring ApplicationContext
---------------------------------

Active Profiles: 3
 prod
 log
 info

-------------------------------------
Reporte Spring SpEL System Properties
-------------------------------------

 spring.profiles.active                     : [prod, log, info]

------------------------------
Reporte Java System Properties
------------------------------

 spring.profiles.active                     : prod,log,info

Here all show the same output - mostly for the 1rst and 2nd based on Spring API - therefore until here no reason to create this post .... but

Beta

if createApplicationContext() contains:

public static ApplicationContext createApplicationContext() {
    ConfigurableApplicationContext ctx =
            new AnnotationConfigApplicationContext("com.manuel.jordan.config");
    System.setProperty("spring.profiles.active", "prod,log,info");
    return ctx;
}

Where it is not the correct approach because the profiles were defined/declared after to create the Spring ApplicationContext, therefore the output is as follows:

---------------------------------
Reporte Spring ApplicationContext
---------------------------------

Active Profiles: 3
 prod
 log
 info

-------------------------------------
Reporte Spring SpEL System Properties
-------------------------------------

 spring.profiles.active                     : null

------------------------------
Reporte Java System Properties
------------------------------

 spring.profiles.active                     : prod,log,info

Question

  • Why getEnvironment().getActiveProfiles() reports the not applied profiles active?

Yes, the profiles were not applied, it was confirmed because the beans based on that profiles were not created. Confirmed through try/catch for NoSuchBeanDefinitionException when is attempted to retrieve them from the ApplicationContext.

Therefore until here at a first glance the correct approach to know the correct list of profiles active is only the based on SpEL and not the one based on getEnvironment().getActiveProfiles() "due the incorrect report" - it generates a confusion if a simple report is need it for debug purposes by taking in consideration what profiles active were applied.

Extra Question

  • Why through SpEL appears the correct list of profiles active?. In this case as empty/null.

This question could be illogical but, it is supposed that the data comes from the same ApplicationContext, right?

In the third report - based on System.getProperty(...) - is compressible because they were declared, but in not in the correct point of time, therefore they are listed but we know they were not really applied.

Manuel Jordan
  • 15,253
  • 21
  • 95
  • 158
  • 2 and 3 are wrong, only 1 is the correct way. 2 and 3 only read the system properties but there are other ways (not through system properties) to define active profiles. Only option 1 will report the actual ones. Why is does report them active because it reads the system property, it will consult all available `PropertySource` instances in the `Environment` for the given property. Your SpEL version runs **before** you set the propert, it will not have that information yet, hence it returns `null`. The same would be if you would use `ctx.getEnvironment().getActiveProfiles()` earlier. – M. Deinum Apr 26 '23 at 07:23
  • About Beta - If 1 is correct, why then the beans were not created? - in that case 2 is correct – Manuel Jordan Apr 26 '23 at 14:27
  • 1
    Martin is right. 2 and 3 are definitely wrong. My best guess is that the environment does not freeze the profile information and it shows the wrong information because you are misusing the API. – Stephane Nicoll Apr 27 '23 at 06:12
  • FTR this thread was duplicated at https://github.com/spring-projects/spring-framework/issues/30385 – Stephane Nicoll Apr 27 '23 at 06:18
  • It doesn't create the beans because you set the property **after** creating the context. The context is fixed and thus doesn't change if you, inflight, update the profiles. – M. Deinum May 09 '23 at 10:24
  • Yes, I did realize the crucial is define the profiles **before** to call direct or indirectly the `refresh` method - otherwise if is declared **after** of the `refresh` method - they are ignored. – Manuel Jordan May 09 '23 at 12:51

0 Answers0