Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How Can I make Spring-MVC @PropertySources load first, before any other configuration

I have a spring-mvc application that is using java configuration, not xml. There are @Configuration annotations sprinkled through several files. In particular, there is a @PropertySources annotation in one file in a class that implements WebMvcConfigurerAdapter. There are two classes which contain an @Autowired Environment variable. One of these classes is itself a @Configuration class, and I would like it to have access to the fully-loaded Environment at the time it runs.

This isn't happening. When this code executes, the Environment is still null. I've tried reordering the @ComponentScan packages, tried moving the @PropertySources annotation, and nothing has helped me load the property sources in time.

I want this to happen first, before any other configuration.

What must I do to make it so?

UPDATE: After trying many things, including the Order annotation, I find the problem seems to be not so much that the @PropertySources are being loaded too late as that a class I have that is derived from org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer is being loaded too soon. Nothing in my code even references this class but Spring is somehow deciding that this, above all other classes, must be initialized first. No amount of messing around with @Order seems to change this. This in spite of the javadocs, which indicate that the behavior I want is the default:

Caveats

Subclasses of AbstractDispatcherServletInitializer will register their filters before any other Filter. This means that you will typically want to ensure subclasses of AbstractDispatcherServletInitializer are invoked first. This can be done by ensuring the Order or Ordered of AbstractDispatcherServletInitializer are sooner than subclasses of AbstractSecurityWebApplicationInitializer.

like image 275
Steve Cohen Avatar asked Dec 20 '25 21:12

Steve Cohen


1 Answers

You can use ContextInitializer, catch the moment when Boot prepared its environment and "inject" your property source programmatically as you want. If you have a ConfigurableApplicationContext then it provides a ConfigurableEnvironment, which contains the propertySources as a list. If you want your PropertySource to rule all above the others than add it as first. If you want to place it to a special position then you can add it before an other, identified by its "name".

public class ConfigInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
    @Override
    public void initialize(ConfigurableApplicationContext ctx) {

    // rule over all the others: 
    ctx.getEnvironment().getPropertySources().
      addFirst(new ResourcePropertySource("file:/etc/conf/your_custom.properties"));

    // rule over application.properties but not argument or systemproperties etc
    ctx.getEnvironment().getPropertySources().
      addBefore("applicationConfig: [classpath:/application.properties]",
      new ResourcePropertySource("classpath:your_custom.properties"));

    // names can be discovered by placing a breakpoint somewhere here and watch 
    // ctx.getEnvironment().getPropertySources().propertySourceList members,
    // each has a name ...
    }
}

You can bring into play this class by:

  • registering it in the application.properties :
    context.initializer.classes=a.b.c.ConfigInitializer
  • or from application start :
    new SpringApplicationBuilder(YourApplication.class).
      initializers(new ConfigInitializer()).
      run(args);

By the way this is a proper way to inject more of your custom properties, like properties coming from a database or a different host etc...

like image 129
László Báthory Avatar answered Dec 24 '25 11:12

László Báthory



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!