How can i externalize datasource configuration wit

2019-05-10 06:16发布

I'm currently trying to move an existing spring-application to spring-boot and therefore recreate things that worked without boot.

I want to configure some properties (like spring.datasource.*) from an external source. specificly a folder with several properties files.

I set up a configuration class that creates propertyPlaceholder configurers like this:

@Configuration
public class PropertySourceConfiguration {

@Bean
public static PropertySourcesPlaceholderConfigurer defaultsPlaceHolderConfigurer() throws IOException {
    PropertySourcesPlaceholderConfigurer propertyConfigurer = new PropertySourcesPlaceholderConfigurer();
    propertyConfigurer.setLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:/*-defaults.properties"));
    propertyConfigurer.setIgnoreUnresolvablePlaceholders(true);
    return propertyConfigurer;
}

@Bean
public static PropertySourcesPlaceholderConfigurer externalPlaceHolderConfigurer() throws IOException {
    PropertySourcesPlaceholderConfigurer propertyConfigurer = new PropertySourcesPlaceholderConfigurer();
    propertyConfigurer.setLocations(new
            PathMatchingResourcePatternResolver().getResources("file:/my-config-path/*.properties"));
    propertyConfigurer.setOrder(1);
    propertyConfigurer.setIgnoreUnresolvablePlaceholders(true);
    return propertyConfigurer;
}

This seems to work for most things (like amqp or my own config properties) but when i try to use spring-data-jpa they are ignored. basicly setting spring.datasource.url (and other things used for auto-config) in those files has no effect.

looking through the logs of the PropertySourcesPropertyResolver i figured out that these configurer fall under the localProperties group which is not used when looking for spring.datasource.*.

is there a way to fix this or a better way to add external properties files to my context?

I know i could set spring.config.location to do something similar but i can not pass command-line properties to my application and need to do this config from within my application. afaik this is not possible with this property.

EDIT: setting spring.config.location:

Attempt 1:

public class ServletInitializer extends SpringBootServletInitializer {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(CampaignServiceStarter.class);
    }
    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        super.onStartup(servletContext);
        servletContext.setInitParameter("spring.config.location", "file:/my-config-path/*.properties");
    }
}

Attempt 2:

public class ServletInitializer extends SpringBootServletInitializer {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(CampaignServiceStarter.class).properties("spring.config.location=file:/my-config-path/*.properties");
    }
}

in both cases the external properties were not picked up at all (even in places where it worked before, like the amqp config)

1条回答
2楼-- · 2019-05-10 07:09

How to use external configuration is explained in this section of the Spring Boot Reference Guide.

The spring.config.location is a path to the directory which contains your application.properties file. It takes a comma separated list of values so you could specify multiple paths. It doesn't take the wildcard. It is a path so not an expression to match multiple property files. If you want to change the default application then use the spring.config.name to make it something else.

The defaults of Spring Boot are opinionated as the rest of Spring Boot (with the default configuration etc.).

If you want to do more extensive (pre) configuration you should use an ApplicationContextInitializer to manually add the PropertySources to the Environment. This is mentioned here in the Spring Boot Reference Guide.

An example of how the initializer might look.

public class ConfigurationInitializer implements ApplicationContextInitializer {

    private static final String DEFAULT_PROPS = "classpath*:/*-defaults.properties";
    private static final String EXTERNAL_PROPS = "file:/my-config-path/*.properties";

    public void initialize(ConfigurableApplicationContext applicationContext) {
        final Resource[] defaultConfigs = applicationContext.getResources(DEFAULT_PROPS);
        final Resource[] externalConfigs = applicationContext.getResources(EXTERNAL_PROPS);

        final ConfigurableEnvironment env = applicationContext.getEnvironment();
        final MutablePropertySources mps =  env.getPropertySources();
        for (Resource r : externalConfigs) {
            mps.addLast(new ResourcePropertySource(r.getFilename(), r);
        }
        for (Resource r : defaultConfigs) {
            mps.addLast(new ResourcePropertySource(r.getFilename(), r);
        }   
    }
}

Then when building your application object add it as follows.

public class ServletInitializer extends SpringBootServletInitializer {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(CampaignServiceStarter.class)
            .initializers(new ConfigurationInitializer());
    }
}

Now the configs should be added to the list of property sources.

查看更多
登录 后发表回答