title: Spring Boot 2 - Do something before the beans are initialized
body: <h3>Problem Statement</h3>
  
  <p>I want to load properties from a properties file in a classpath or at an external location before the beans are initialized. These properties are also a part of Bean initialization. I cannot autowire the properties from Spring's standard <em>application.properties</em> or its customization because the same properties file must be accessible by multiple deployables.</p>
  
  <h3>What I Tried</h3>
  
  <p>I'm aware about <a href="https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#boot-features-application-events-and-listeners" rel="noreferrer">Spring Application Events</a>; in fact, I'm already hooking 
  <em>ContextRefreshedEvent</em> to perform some tasks after the Spring Context is initialized (Beans are also initialized at this stage).</p>
  
  <p>For my problem statement, from the description of Spring Docs <code>ApplicationEnvironmentPreparedEvent</code> looked promising, but the hook did not work.</p>
  
  <pre><code>
  @SpringBootApplication
  public class App {
  
      public static void main(String[] args) throws IOException {
          SpringApplication.run(App.class, args);
      }
  
  
      @EventListener
      public void onStartUp(ContextRefreshedEvent event) {
          System.out.println("ContextRefreshedEvent");    // WORKS
      }
  
      @EventListener
      public void onShutDown(ContextClosedEvent event) {
          System.out.println("ContextClosedEvent");   // WORKS
      }
  
      @EventListener
      public void onEvent6(ApplicationStartedEvent event) {
          System.out.println("ApplicationStartedEvent");  // WORKS BUT AFTER ContextRefreshedEvent
      }
  
  
      @EventListener
      public void onEvent3(ApplicationReadyEvent event) {
          System.out.println("ApplicationReadyEvent");    // WORKS WORKS BUT AFTER ContextRefreshedEvent
      }
  
  
      public void onEvent1(ApplicationEnvironmentPreparedEvent event) {
          System.out.println("ApplicationEnvironmentPreparedEvent");  // DOESN'T WORK
      }
  
  
      @EventListener
      public void onEvent2(ApplicationContextInitializedEvent event) {
          System.out.println("ApplicationContextInitializedEvent");   // DOESN'T WORK
      }
  
  
      @EventListener
      public void onEvent4(ApplicationContextInitializedEvent event) {
          System.out.println("ApplicationContextInitializedEvent");
      }
  
      @EventListener
      public void onEvent5(ContextStartedEvent event) {
          System.out.println("ContextStartedEvent");
      }
  
  }
  
  </code></pre>
  
  <h3>Update</h3>
  
  <p>As suggested by <em>M.Deinum</em> in the comments, I tried adding an application context initializer like below. It doesn't seem to be working either.</p>
  
  <pre><code>    public static void main(String[] args) {
          new SpringApplicationBuilder()
                  .sources(App.class)
                  .initializers(applicationContext -&gt; {
                      System.out.println("INSIDE CUSTOM APPLICATION INITIALIZER");
                  })
                  .run(args);
  
      }
  </code></pre>
  
  <h3>Update #2</h3>
  
  <p>While my problem statement is regarding loading properties, my question/curiosity is really about <strong>how to run some code before the classes are initialized as beans and put into Spring IoC container</strong>. Now, these beans require some property values during initialization and I can't/don't want to Autowire them because of the following reason:</p>
  
  <p>As stated in comments and answers, the same can be done using Spring Boot's externalized configuration and profiles. However, I need to maintain application properties and domain-related properties separately. A base domain properties should have at least 100 properties, and the number grows over time. Both application properties and domain-related properties have a property file for different environments (dev, SIT, UAT, Production). Property files override one or more of the base properties. That's 8 property files. Now, the same app needs to be deployed into multiple geographies. That makes it <code>8 * n</code> property files where <code>n</code> is the number of geographies. I want all the property files stored in a common module so that they can be accessed by different deployables. Environment and geography would be known in run-time as system properties.</p>
  
  <p>While these might be achieved by using Spring profiles and precedence order, I want to have a programmatic control over it (<strong>I also would maintain my own property repository</strong>). Eg. I would write a convenience utility called <code>MyPropUtil</code> and access them like:</p>
  
  <pre><code>public class MyPropUtil {
       private static Map&lt;String, Properties&gt; repository;
  
       public static initialize(..) {
           ....
       }
  
       public static String getDomainProperty(String key) {
          return repository.get("domain").getProperty(key);
       }
  
       public static String getAppProperty(String key) {
           return repository.get("app").getProperty(key);
       }
  
       public static String getAndAddBasePathToAppPropertyValue(String key) {
          ...
       }
  
  }
  
  </code></pre>
  
  <pre><code>@Configuration
  public class MyComponent {
  
      @Bean
      public SomeClass getSomeClassBean() {
          SomeClass obj = new SomeClass();
          obj.someProp1(MyPropUtil.getDomainProperty('domainkey1'));
          obj.someProp2(MyPropUtil.getAppProperty('appkey1'));
          // For some properties
           obj.someProp2(MyPropUtil.getAndAddBasePathToAppPropertyValue('some.relative.path.value'));
          ....
          return obj;
      }
  
  }
  </code></pre>
  
  <p>From the docs, it seems like <code>ApplicationEvents</code> and <code>ApplicationInitializers</code> fit my need, but I am not able to get them to work for my problem statement.</p>