LynxZh LynxZh - 5 months ago 96
Java Question

Spring data multiple datasources from multiple files

I have 2 (or more) different configuration properties file located in the project and I want to load them for different datasources.

I tried to do as following:

@Bean
@ConfigurationProperties(locations = {"#{myconfigroot.getRootFolder()}/datasource1.properties"}
public static DataSource getFirstDatasource() {
return DataSourceBuilder.create().build();
}


But obviously this won't work as the ConfigurationProperties annotation locations property doesn't go through the spEL. (Or may be I write it wrong?) myconfigroot.getRootFolder() is a static method which returns the path to the datasource1.properties.

Please advice. Thanks.

===== Edited =======

I believe this is a common problem when somebody want their application want to load different configuration files. Due to some reasons the file location and name can't be put in the startup script or command line, or, the path can only be determined in runtime, that would require spring to load them during the bean creation.

I tried once using PropertySourcePlaceHolderConfigurer but seems not work either.

Anybody can share some lights?

Answer

Latest Spring boot (version 1.3.5) doesn’t support SpEL in this case.

See JavaDoc of annotation @ConfigurationProperties

Note that contrary to {@code @Value}, SpEL expressions are not evaluated since property values are externalized.

I found a way to customize Spring boot default behavior as follows:

For example, I have database.properties file in somewhere, for some reason I cannot get the location before runtime.

username=mike
password=password

Accordingly, define POJO mapping to properties:

@Component
@ConfigurationProperties(locations = "myConfiguration")// myConfiguration is customized placeholder
public class MyProperties{
   String username;
   String password;
   //Getters, Setters…
}

Then, to extend default StandardEnvironment:

public class MyEnvironment extends StandardEnvironment {
   @Override
   public String resolvePlaceholders(String location) {
      if (location.equals("myConfiguration")) {
         //Whatever you can do, SpEL, method call...
         //Return database.properties path at runtime in this case
         return getRootFolder() + "datasource.properties"; 
      } else {
         return super.resolvePlaceholders(text);
      }
   }
}

Last, apply it in Spring boot main method entry:

@SpringBootApplication
public class MyApplication extends SpringBootServletInitializer {
public static void main(String[] args) {
    new SpeedRestApplication()
        .configure(new SpringApplicationBuilder(SpeedRestApplication.class).environment(new MyEnvironment()))//Replace default StandardEnvironment
        .run(args);
   }
}

Once Spring boot starts up, the MyProperties bean name and password fields are injected from database.properties. Then you could wire the MyProperties bean to other beans as configuration.

Hope it helps!

Comments