如何使用spring boot将数据源配置外部化?

如何使用spring boot将数据源配置外部化?,spring,spring-boot,spring-data-jpa,Spring,Spring Boot,Spring Data Jpa,我目前正在尝试将现有的spring应用程序移动到spring boot,从而重新创建在没有启动的情况下工作的东西 我想从外部源配置一些属性(如spring.datasource.*)。具体地说是一个包含多个属性文件的文件夹 我设置了一个配置类来创建propertyPlaceholder配置器,如下所示: @Configuration public class PropertySourceConfiguration { @Bean public static PropertySourcesPla

我目前正在尝试将现有的spring应用程序移动到spring boot,从而重新创建在没有启动的情况下工作的东西

我想从外部源配置一些属性(如spring.datasource.*)。具体地说是一个包含多个属性文件的文件夹

我设置了一个配置类来创建propertyPlaceholder配置器,如下所示:

@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;
}
这似乎适用于大多数情况(如amqp或我自己的配置属性),但当我尝试使用SpringDataJPA时,它们被忽略了。基本上,在这些文件中设置
spring.datasource.url
(以及用于自动配置的其他内容)没有效果

通过查看
PropertySourcesPropertyResolver
的日志,我发现这些配置器属于
localProperties
组,在查找
spring.datasource.
时不使用该组

有没有办法解决这个问题,或者有更好的办法将外部属性文件添加到我的上下文中

我知道我可以设置
spring.config.location
来执行类似的操作,但我无法将命令行属性传递给我的应用程序,需要在应用程序中执行此配置。A好的,这在这个属性中是不可能的

编辑:设置
spring.config.location

尝试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");
    }
}
尝试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");
    }
}

在这两种情况下,外部属性根本没有被获取(即使在它以前工作过的地方,如amqp配置)

如何使用外部配置在《Spring引导参考指南》的一部分中进行了解释

是指向包含
应用程序.properties
文件的目录的路径。它采用逗号分隔的值列表,因此可以指定多个路径。它不需要通配符。它是一个路径,因此不是匹配多个属性文件的表达式。如果要更改默认的
应用程序
,请使用
spring.config.name
使其成为其他应用程序

SpringBoot的默认设置与SpringBoot的其余部分一样(默认配置等)

如果要进行更广泛的(预)配置,应使用
ApplicationContextInitializer
PropertySource
手动添加到
环境中。这在Spring Boot参考指南中提到

初始值设定项的外观示例

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);
        }   
    }
}
然后在构建应用程序对象时,按如下方式添加它

public class ServletInitializer extends SpringBootServletInitializer {

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

现在,应该将配置添加到属性源列表中。

只需将
@PropertySource
添加到配置中,而不要添加其他
propertySourcesplaceConfigurer
s。或者添加一个添加其他属性源的
ApplicationContextInitializer
。但你目前的解决方案行不通。还有,为什么不把所有的东西都放在
application.properties
中,让spring boot来处理所有的事情呢?为什么不把所有的
applicaton.properties
文件放在一起呢:因为不同的环境(如美国/欧盟/登台等)需要不同的配置。没有办法用占位符做到这一点吗
@PropertySources
不支持此功能。为什么需要由开发人员进行维护?如果它位于同一目录或配置目录中,则任何有权访问服务器的人都可以对其进行维护。还有,为什么不能将属性传递给应用程序?如果有main方法,可以修改传入参数列表并添加
spring.config.location
如果使用
SpringBootServletInitializer
可以将其添加为默认参数。还要注意,它不一定是命令行属性JNDI或环境变量。它是一个位置而不是模式,此位置用于搜索
应用程序.properties
文件(以及嵌套的
配置
位置)。因此,它应该类似于
spring.config.location=file:/my config path
,可以使用逗号分隔的值来包含多个路径。要更改文件名,请使用
spring.config.name
。spring引导有自己的默认设置。此外,通配符(可能)相当麻烦,因为您无法控制加载这些文件的顺序。也可能是危险的,因为如果有人不小心将道具文件放在了错误的目录中,您的应用程序可能会崩溃。如果确实需要,您可以(并且应该)实现一个
ApplicationContextListener
,并将
PropertySource
s添加到
环境中。此解决方案的问题是日志属性将被忽略,类似logback的日志系统将无法工作。我正在研究这个问题,并找到了一个解决方案,该解决方案还可以加载日志属性,基本上
spring.config.location
必须在开始时设置,当配置spring引导时,您可以检查它