简体   繁体   中英

How to inject extra property sources in SPRING before other beans are created?

I am writing a library which will be used by spring-boot projects. I'd like to inject into the boot projects' SpringEnvironment a property source that I take from the Internet.

I tried the following

@Configuration
public class MyCustomConfiguration {

  @Bean
  BeanDefinedAbove above() { /* do some work */ }

  @Bean
  @ConditionalOnBean(BeanDefinedAbove.class)
  SmartInitializingSingleton propertySourceSetting(ConfigurableEnvironment env, BeanDefinedAbove bean) {
    return () -> { 
      PropertySource source = bean.getPropertySourceDownloadedFromTheInternet();
      env.getPropertySources().addFirst(source);
    }
  }
}

In my clients' projects when I debug this code what happens is either one of the two:

  1. above() is called
  2. user's @Service or @Controller are called
  3. propertySourceSetting(...) is called

OR

  1. user's @Service or @Controller are called
  2. above() is called
  3. propertySourceSetting(...) is called

Depending whether or not my client's depend on my BeanDefinedAbove bean, which is normal as the @Service is depdent on the bean created in above() .

I have also added the FQDN of my class to the EnableAutoConfiguration in the META-INF/spring.factories .

So how to ensure that the logic in propertySourceSetting(..) is called before users' @Service and @Controller

I'll provide you with three options.

Option 1: (THIS IS A BAD APPROACH, BUT A QUICK WORKAROUND)

Add @Lazy(false) annotation to both Beans. Spring will eagerly create those two beans, which they will probably be created before the other ones.

Why this is bad? This does not ensure order. Spring decides the creation order based on dependencies and some other conditions. This is why it will "probably" work :)

Option 2: Create a main class to bootstrap Spring Boot Initialization (the old way of starting spring boot).

public static void main(String[] args) throws Exception {
   SpringApplication application = new SpringApplication(MyApplication.class);
   // ... add property source here before start
   application.run(args)
 }

You also need to specify main class in the manifest for Spring Boot like this: https://www.baeldung.com/spring-boot-main-class

In that main-class you would add your propertysource, kinda like this:

SomeClassThatRetrievesProperties propRetriever = new SomeClassThatRetrievesProperties ();
Map<String,String> properties = propRetriever.getAllPropertiesAsMap(); 
application.setDefaultProperties(properties);

Option 3 : Create a CustomApplicationContext by extending WebApplicationContext and overriding getSpecificConfigurations() method.

This way you will have full control but we aware that you could break some important stuff.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM