Spring Boot e vários arquivos de configuração externos


125

Eu tenho vários arquivos de propriedades que quero carregar do caminho de classe. Há um conjunto padrão no /src/main/resourcesqual faz parte myapp.jar. Meu springcontextespera que os arquivos estejam no caminho de classe. ie

<util:properties id="Job1Props"
    location="classpath:job1.properties"></util:properties>

<util:properties id="Job2Props"
    location="classpath:job2.properties"></util:properties>

Também preciso da opção de substituir essas propriedades por um conjunto externo. Eu tenho uma pasta de configuração externa cwd. Conforme a pasta de configuração do documento de inicialização da primavera, a pasta deve estar no caminho de classe. Mas não está claro no doc se ele substituirá apenas o applicaiton.propertiesde lá ou todas as propriedades em config.

Quando o testei, apenas application.propertiesé apanhada e o restante das propriedades ainda são apanhadas /src/main/resources. Tentei fornecê-los como lista separada por vírgulas, spring.config.locationmas o conjunto padrão ainda não está sendo substituído.

Como faço para que vários arquivos de configuração externos substituam os padrão?

Como solução alternativa, usei atualmente app.config.location(propriedade específica do aplicativo) que forneço através da linha de comando. ie

java -jar myapp.jar app.config.location=file:./config

e mudei applicationcontextpara

<util:properties id="Job2Props"
    location="{app.config.location}/job2.properties"></util:properties>

E é assim que faço a separação entre arquivo e caminho de classe ao carregar o aplicativo.
EDITAR% S:

//psuedo code

if (StringUtils.isBlank(app.config.location)) {
            System.setProperty(APP_CONFIG_LOCATION, "classpath:");
}

Eu realmente gostaria de não usar a solução alternativa acima e o Spring substitui todos os arquivos de configuração externos no caminho de classe, como acontece com o application.propertiesarquivo.


4
O application.propertiessempre será carregado, com spring.config.locationvocê poderá adicionar locais de configuração adicionais que são verificados quanto a arquivos (ou seja, quando termina com a /), no entanto, se você colocar uma lista separada por vírgulas, indicando os arquivos que serão carregados. Isso também é explicado no Spring Boot Reference Guide aqui
M. Deinum

Respostas:


154

Ao usar o Spring Boot, as propriedades são carregadas na seguinte ordem (consulte Configuração externalizada no guia de referência do Spring Boot).

  1. Argumentos de linha de comando.
  2. Propriedades do sistema Java (System.getProperties ()).
  3. Variáveis ​​de ambiente do SO.
  4. Atributos JNDI de java: comp / env
  5. Um RandomValuePropertySource que possui apenas propriedades aleatoriamente. *.
  6. Propriedades do aplicativo fora do seu jar empacotado (application.properties incluindo YAML e variantes de perfil).
  7. Propriedades do aplicativo empacotadas dentro do seu jar (application.properties incluindo YAML e variantes de perfil).
  8. Anotações @PropertySource nas suas classes @Configuration.
  9. Propriedades padrão (especificadas usando SpringApplication.setDefaultProperties).

Ao resolver propriedades (ou seja, a @Value("${myprop}")resolução é feita na ordem inversa (iniciando com 9)).

Para adicionar arquivos diferentes, você pode usar as spring.config.locationpropriedades que usam uma lista separada por vírgula de arquivos de propriedade ou local do arquivo (diretórios).

-Dspring.config.location=your/config/dir/

O acima irá adicionar um diretório que será consultado para application.propertiesarquivos.

-Dspring.config.location=classpath:job1.properties,classpath:job2.properties

Isso adicionará o arquivo de 2 propriedades aos arquivos carregados.

Os arquivos e locais de configuração padrão são carregados antes dos especificados adicionalmente spring.config.location, o que significa que os últimos sempre substituirão as propriedades definidas nos anteriores. (Consulte também esta seção do Guia de Referência do Boot Spring).

Se spring.config.locationcontiver diretórios (ao contrário de arquivos), eles deverão terminar em / (e serão anexados aos nomes gerados spring.config.nameantes de serem carregados). O caminho de pesquisa padrão classpath:,classpath:/config,file:,file:config/é sempre usado, independentemente do valor de spring.config.location. Dessa forma, você pode configurar os valores padrão para seu aplicativo application.properties(ou qualquer outro nome de base que você escolher spring.config.name) e substituí-lo no tempo de execução por um arquivo diferente, mantendo os padrões.

ATUALIZAÇÃO: como o comportamento de spring.config.location agora substitui o padrão em vez de adicionar a ele. Você precisa usar spring.config.additional-location para manter os padrões. Essa é uma alteração no comportamento de 1.x para 2.x


2
Obrigado, mas eu já li este documento de referência e o seguinte é confuso para mim "-Dspring.config.location = your / config / dir / O exemplo acima adicionará um diretório que será consultado para os arquivos application.properties." O que significa arquivos application.properties. Esse é apenas um arquivo. De qualquer forma, se ele conseguir pegar o diretório inteiro com "/" no final, não será necessário especificar cada um como lista separada por vírgula. Eu acho que tentei ambas as abordagens, como mencionei no meu post, mas vou tentar mais uma vez
nir 16/09/14

Conforme indicado no documento, ele será consultado como os outros locais padrão para application.propertiese application-[env].properties. Não leva em consideração outros arquivos de propriedades. Isso também é afirmado no guia de referência (na seção ao qual o link leva e na citação do guia de referência).
M. Deinum

1
Sim, mas é isso que não faz sentido para mim .. por que considerar apenas um tipo de arquivo de um diretório no caminho de classe em vez do diretório inteiro. Isso obriga a usar apenas um arquivo de propriedades que não é bom para imo. Como no tomcat, eu posso configurar o common.loader para colocar um diretório específico (e tudo dentro dele) no caminho de classe, por que o carregador de classes não pode inicializá-lo.
nir 17/09/14

3
Citar a documentação não é útil. Se a documentação fosse clara (o suficiente? Da maneira particularmente necessária?), A pergunta não seria necessária. Por exemplo, nesse caso, não está realmente claro como config.locatione config.namesinteragir, embora provavelmente pareça claro para as pessoas que já sabem como interagem. Você pode atualizar sua resposta para adicionar algo à documentação?
Narfanator 28/02

13
Isso deve ser atualizado, pois o comportamento de spring.config.locationagora substitui o padrão em vez de adicionar a ele. Você precisa usar spring.config.additional-locationpara manter os padrões. Essa é uma alteração no comportamento de 1.x para 2.x.
22618 Robin

32

Com a inicialização do Spring, o spring.config.location funciona, basta fornecer arquivos de propriedades separados por vírgula.

veja o código abaixo

@PropertySource(ignoreResourceNotFound=true,value="classpath:jdbc-${spring.profiles.active}.properties")
public class DBConfig{

     @Value("${jdbc.host}")
        private String jdbcHostName;
     }
}

pode-se colocar a versão padrão do jdbc.properties dentro do aplicativo. As versões externas podem ser configuradas aqui.

java -jar target/myapp.jar --spring.config.location=classpath:file:///C:/Apps/springtest/jdbc.properties,classpath:file:///C:/Apps/springtest/jdbc-dev.properties

Com base no valor do perfil configurado usando a propriedade spring.profiles.active, o valor de jdbc.host será escolhido. Então, quando (no Windows)

set spring.profiles.active=dev

O jdbc.host terá o valor de jdbc-dev.properties.

para

set spring.profiles.active=default

jdbc.host terá valor de jdbc.properties.


Não acredito que o primeiro bloco de código funcione. Eu sei que me apaguei neste e segui esta resposta . Veja jira.springsource.org/browse/SPR-8539 referenciado na resposta para uma explicação decente.
Sowka

27

Spring boot 1.X e Spring Boot 2.X não fornecem as mesmas opções e comportamento sobre o Externalized Configuration.

A resposta muito boa de M. Deinum refere-se às especificações da Bota de Primavera 1.
Vou atualizar para o Spring Boot 2 aqui.

Origens e ordem das propriedades do ambiente

O Spring Boot 2 usa uma PropertySourceordem muito específica , projetada para permitir a substituição sensata de valores. As propriedades são consideradas na seguinte ordem:

  • Propriedades de configurações globais do Devtools em seu diretório pessoal (~ / .spring-boot-devtools.properties quando o devtools está ativo).

  • @TestPropertySource anotações em seus testes.

  • @SpringBootTest#propertiesatributo de anotação em seus testes. Argumentos de linha de comando.

  • Propriedades de SPRING_APPLICATION_JSON(JSON embutido incorporado em uma variável de ambiente ou propriedade do sistema).

  • ServletConfig parâmetros init.

  • ServletContext parâmetros init.

  • Atributos JNDI de java:comp/env.

  • Propriedades do sistema Java ( System.getProperties()).

  • Variáveis ​​de ambiente do SO.

  • A RandomValuePropertySourceque possui propriedades apenas aleatoriamente. *.

  • Propriedades de aplicativo específicas do perfil fora do seu jar empacotado ( application-{profile}.propertiese variantes YAML).

  • Propriedades de aplicativo específicas do perfil empacotadas dentro do seu jar ( application-{profile}.propertiese variantes YAML).

  • Propriedades do aplicativo fora do seu jar empacotado ( application.propertiese variantes YAML).

  • Propriedades do aplicativo empacotadas dentro do seu jar ( application.propertiese variantes YAML).

  • @PropertySourceanotações em suas @Configurationaulas. Propriedades padrão (especificadas pela configuração SpringApplication.setDefaultProperties).

Para especificar arquivos de propriedades externas, essas opções devem interessar:

  • Propriedades de aplicativo específicas do perfil fora do seu jar empacotado ( application-{profile}.propertiese variantes YAML).

  • Propriedades do aplicativo fora do seu jar empacotado ( application.propertiese variantes YAML).

  • @PropertySourceanotações em suas @Configurationaulas. Propriedades padrão (especificadas pela configuração SpringApplication.setDefaultProperties).

Você pode usar apenas uma dessas 3 opções ou combiná-las de acordo com seus requisitos.
Por exemplo, para casos muito simples, usar apenas propriedades específicas do perfil é suficiente, mas em outros casos, convém usar as propriedades específicas do perfil, as propriedades padrão e@PropertySource .

Locais padrão para arquivos application.properties

Sobre application.propertiesarquivos (e variante), por padrão, o Spring os carrega e adiciona suas propriedades no ambiente a partir deles na seguinte ordem:

  • Um subdiretório / config do diretório atual

  • O diretório atual

  • Um pacote classpath / config

  • A raiz do caminho de classe

As prioridades mais altas são tão literalmente:
classpath:/,classpath:/config/,file:./,file:./config/.

Como usar arquivos de propriedades com nomes específicos?

Os locais padrão nem sempre são suficientes: os locais padrão, como o nome do arquivo padrão ( application.properties), podem não ser adequados. Além disso, como na pergunta OP, pode ser necessário especificar vários arquivos de configuração além de application.properties(e variante).
Então spring.config.namenão será suficiente.

Nesse caso, você deve fornecer um local explícito usando a spring.config.locationpropriedade environment (que é uma lista separada por vírgula de locais de diretório ou caminhos de arquivo).
Para ser livre sobre o padrão de nomes de arquivos, favorece a lista de caminhos de arquivos sobre a lista de diretórios.
Por exemplo, faça assim:

java -jar myproject.jar --spring.config.location=classpath:/default.properties,classpath:/override.properties

Dessa forma, é a mais detalhada que apenas especifica a pasta, mas também é a maneira de especificar muito bem nossos arquivos de configuração e documentar claramente as propriedades efetivamente usadas.

O spring.config.location agora substitui os locais padrão em vez de adicioná-los

Com o Spring Boot 1, o spring.config.locationargumento adiciona locais especificados no ambiente Spring.
Porém, a partir do Spring Boot 2, spring.config.locationsubstitui os locais padrão usados ​​pelo Spring pelos locais especificados no ambiente Spring, conforme indicado na documentação .

Quando os locais de configuração personalizados são configurados usando spring.config.location, eles substituem os locais padrão. Por exemplo, se spring.config.locationestiver configurado com o valor classpath:/custom-config/, file:./custom-config/a ordem de pesquisa torna-se o seguinte:

  1. file:./custom-config/

  2. classpath:custom-config/

spring.config.locationAgora é uma maneira de garantir que qualquer application.propertiesarquivo precise ser especificado explicitamente.
Para JARs uber que não devem empacotarapplication.properties arquivos, isso é bastante agradável.

Para manter o comportamento antigo de spring.config.locationusar o Spring Boot 2, você pode usar a nova spring.config.additional-locationpropriedade em vez de spring.config.locationainda adicionar os locais, conforme declarado na documentação :

Como alternativa, quando locais de configuração personalizados são configurados usando spring.config.additional-location, eles são usados ​​além dos locais padrão.


Na prática

Então, supondo que, como na pergunta OP, você tenha 2 arquivos de propriedades externas para especificar e 1 arquivo de propriedades incluídos no uber jar.

Para usar apenas os arquivos de configuração especificados:

-Dspring.config.location=classpath:/job1.properties,classpath:/job2.properties,classpath:/applications.properties   

Para adicionar arquivos de configuração a eles nos locais padrão:

-Dspring.config.additional-location=classpath:/job1.properties,classpath:/job2.properties

classpath:/applications.properties não é necessário no último exemplo, pois os locais padrão têm isso e esses locais padrão não são substituídos, mas estendidos.


Sua resposta é realmente completa, exceto por uma coisa: onde o Spring encontrará a configuração externa job1.properties no disco se você especificar: "classpath: /job1.properties"? Como você adicionou seu diretório que contém propriedades externas ao caminho de classe aqui?
Tristan

@Tristan, basicamente, o spring pode ler um application.propertiescom todos os parâmetros e vários ${file_name}.propertiescom conjuntos de propriedades parciais definidos. Portanto, se você usar @PropertySourceou outros links fortes para arquivos, poderá criar outro arquivo externo e substituir essas propriedades (por exemplo: de classpath:file.properties).
Mister_Jesus

23

Dê uma olhada no PropertyPlaceholderConfigurer, acho mais claro que a anotação.

por exemplo

@Configuration
public class PropertiesConfiguration {


    @Bean
    public PropertyPlaceholderConfigurer properties() {
        final PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
//        ppc.setIgnoreUnresolvablePlaceholders(true);
        ppc.setIgnoreResourceNotFound(true);

        final List<Resource> resourceLst = new ArrayList<Resource>();

        resourceLst.add(new ClassPathResource("myapp_base.properties"));
        resourceLst.add(new FileSystemResource("/etc/myapp/overriding.propertie"));
        resourceLst.add(new ClassPathResource("myapp_test.properties"));
        resourceLst.add(new ClassPathResource("myapp_developer_overrides.properties")); // for Developer debugging.

        ppc.setLocations(resourceLst.toArray(new Resource[]{}));

        return ppc;
    }

Muito obrigado por esta resposta. Você pode me informar como posso obter o mesmo em um projeto que possui configurações XML semelhantes para coisas diferentes sem um arquivo XML base? Sua resposta acima me ajudou em outro projeto que foi baseado em anotações. Mais uma vez obrigado por isso.
Chetan

8

esta é uma abordagem simples usando a bota de mola

TestClass.java

@Configuration
@Profile("one")
@PropertySource("file:/{selected location}/app.properties")
public class TestClass {

    @Autowired
    Environment env;

    @Bean
    public boolean test() {
        System.out.println(env.getProperty("test.one"));
        return true;
    }
}

o contexto app.properties , em seu local selecionado

test.one = 1234

seu aplicativo de inicialização de primavera

@SpringBootApplication

public class TestApplication {

    public static void main(String[] args) {
        SpringApplication.run(testApplication.class, args);
    }
}

e o application.properties predefinido contexto

spring.profiles.active = one

você pode escrever quantas classes de configuração desejar e habilitar / desabilitar apenas definindo spring.profiles.active = o nome do perfil / nomes {separados por vírgulas}

como você pode ver, a inicialização por mola é ótima, ela precisa de algum tempo para se familiarizar, vale a pena mencionar que você também pode usar o @Value em seus campos

@Value("${test.one}")
String str;

7

Eu tive o mesmo problema. Eu queria ter a capacidade de substituir um arquivo de configuração interno na inicialização por um arquivo externo, semelhante à detecção application.properties do Spring Boot. No meu caso, é um arquivo user.properties onde os usuários dos meus aplicativos estão armazenados.

Minhas exigências:

Carregue o arquivo nos seguintes locais (nesta ordem)

  1. O caminho da classe
  2. A / config subdiretório do diretório atual.
  3. O diretório atual
  4. Do diretório ou local de um arquivo fornecido por um parâmetro de linha de comando na inicialização

Eu vim com a seguinte solução:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.PathResource;
import org.springframework.core.io.Resource;

import java.io.IOException;
import java.util.Properties;

import static java.util.Arrays.stream;

@Configuration
public class PropertiesConfig {

    private static final Logger LOG = LoggerFactory.getLogger(PropertiesConfig.class);

    private final static String PROPERTIES_FILENAME = "user.properties";

    @Value("${properties.location:}")
    private String propertiesLocation;

    @Bean
    Properties userProperties() throws IOException {
        final Resource[] possiblePropertiesResources = {
                new ClassPathResource(PROPERTIES_FILENAME),
                new PathResource("config/" + PROPERTIES_FILENAME),
                new PathResource(PROPERTIES_FILENAME),
                new PathResource(getCustomPath())
        };
        // Find the last existing properties location to emulate spring boot application.properties discovery
        final Resource propertiesResource = stream(possiblePropertiesResources)
                .filter(Resource::exists)
                .reduce((previous, current) -> current)
                .get();
        final Properties userProperties = new Properties();

        userProperties.load(propertiesResource.getInputStream());

        LOG.info("Using {} as user resource", propertiesResource);

        return userProperties;
    }

    private String getCustomPath() {
        return propertiesLocation.endsWith(".properties") ? propertiesLocation : propertiesLocation + PROPERTIES_FILENAME;
    }

}

Agora, o aplicativo usa o recurso de caminho de classe, mas também procura por um recurso nos outros locais. O último recurso que existe será escolhido e usado. Consigo iniciar meu aplicativo com java -jar myapp.jar --properties.location = / directory / myproperties.properties para usar um local de propriedades que flutua no meu barco.

Um detalhe importante aqui: use uma String vazia como valor padrão para o properties.location na anotação @Value para evitar erros quando a propriedade não estiver configurada.

A convenção para um properties.location é: Use um diretório ou um caminho para um arquivo de propriedades como properties.location.

Se você deseja substituir apenas propriedades específicas, um PropertiesFactoryBean com setIgnoreResourceNotFound (true) pode ser usado com a matriz de recursos definida como locais.

Tenho certeza de que esta solução pode ser estendida para lidar com vários arquivos ...

EDITAR

Aqui está minha solução para vários arquivos :) Como antes, isso pode ser combinado com um PropertiesFactoryBean.

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.PathResource;
import org.springframework.core.io.Resource;

import java.io.IOException;
import java.util.Map;
import java.util.Properties;

import static java.util.Arrays.stream;
import static java.util.stream.Collectors.toMap;

@Configuration
class PropertiesConfig {

    private final static Logger LOG = LoggerFactory.getLogger(PropertiesConfig.class);
    private final static String[] PROPERTIES_FILENAMES = {"job1.properties", "job2.properties", "job3.properties"};

    @Value("${properties.location:}")
    private String propertiesLocation;

    @Bean
    Map<String, Properties> myProperties() {
        return stream(PROPERTIES_FILENAMES)
                .collect(toMap(filename -> filename, this::loadProperties));
    }

    private Properties loadProperties(final String filename) {
        final Resource[] possiblePropertiesResources = {
                new ClassPathResource(filename),
                new PathResource("config/" + filename),
                new PathResource(filename),
                new PathResource(getCustomPath(filename))
        };
        final Resource resource = stream(possiblePropertiesResources)
                .filter(Resource::exists)
                .reduce((previous, current) -> current)
                .get();
        final Properties properties = new Properties();

        try {
            properties.load(resource.getInputStream());
        } catch(final IOException exception) {
            throw new RuntimeException(exception);
        }

        LOG.info("Using {} as user resource", resource);

        return properties;
    }

    private String getCustomPath(final String filename) {
        return propertiesLocation.endsWith(".properties") ? propertiesLocation : propertiesLocation + filename;
    }

}

boa solução alternativa. Assim que java8 constrói! de qualquer forma eu não posso usá-lo, pois eu preciso de vários beans Properties e não apenas um. Se você vir meus EDITS, minha solução alternativa será bem parecida e organizada para o meu caso de uso.
nir

Eu postei uma versão para vários arquivos, apenas para ser completo;)
mxsb

6

A inicialização por mola nos permite escrever perfis diferentes para ambientes diferentes, por exemplo, podemos ter arquivos de propriedades separados para ambientes de produção, qa e locais

O arquivo application-local.properties com configurações de acordo com minha máquina local é

spring.profiles.active=local

spring.data.mongodb.host=localhost
spring.data.mongodb.port=27017
spring.data.mongodb.database=users
spring.data.mongodb.username=humble_freak
spring.data.mongodb.password=freakone

spring.rabbitmq.host=localhost
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
spring.rabbitmq.port=5672

rabbitmq.publish=true

Da mesma forma, podemos escrever application-prod.properties e application-qa.properties quantos arquivos de propriedades desejarmos

depois escreva alguns scripts para iniciar o aplicativo em diferentes ambientes, por exemplo

mvn spring-boot:run -Drun.profiles=local
mvn spring-boot:run -Drun.profiles=qa
mvn spring-boot:run -Drun.profiles=prod

5

Acabei de ter um problema semelhante a esse e finalmente descobri a causa: o arquivo application.properties tinha os atributos incorretos de propriedade e rwx. Portanto, quando o tomcat inicializou, o arquivo application.properties estava no local certo, mas de propriedade de outro usuário:

$ chmod 766 application.properties

$ chown tomcat application.properties

Eu acho que tenho um problema semelhante. Eu instalei o tomcat na pasta opt. Onde você colocou seu arquivo de aplicativo? Também devo alterar os atributos da pasta?
precisa saber é o seguinte

3

Uma versão modificada da solução @mxsb que nos permite definir vários arquivos e, no meu caso, são arquivos yml.

Na minha aplicação-dev.yml, adicionei esta configuração que me permite injetar todos os yml que possuem -dev.yml. Essa também pode ser uma lista de arquivos específicos. "caminho da classe: /test/test.yml, caminho da classe: /test2/test.yml"

application:
  properties:
    locations: "classpath*:/**/*-dev.yml"

Isso ajuda a obter um mapa de propriedades.

@Configuration

public class PropertiesConfig {

private final static Logger LOG = LoggerFactory.getLogger(PropertiesConfig.class);

@Value("${application.properties.locations}")
private String[] locations;

@Autowired
private ResourceLoader rl;

@Bean
Map<String, Properties> myProperties() {
    return stream(locations)
            .collect(toMap(filename -> filename, this::loadProperties));
}

private Properties loadProperties(final String filename) {

    YamlPropertySourceLoader loader = new YamlPropertySourceLoader();
    try {
        final Resource[] possiblePropertiesResources = ResourcePatternUtils.getResourcePatternResolver(rl).getResources(filename);
        final Properties properties = new Properties();
        stream(possiblePropertiesResources)
                .filter(Resource::exists)
                .map(resource1 -> {
                    try {
                        return loader.load(resource1.getFilename(), resource1);
                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    }
                }).flatMap(l -> l.stream())
                .forEach(propertySource -> {
                    Map source = ((MapPropertySource) propertySource).getSource();
                    properties.putAll(source);
                });

        return properties;
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
}
}

No entanto, se assim for no meu caso, eu queria dividir arquivos yml para cada perfil e carregá-los e injetá-los diretamente na configuração de primavera antes da inicialização dos beans.

config
    - application.yml
    - application-dev.yml
    - application-prod.yml
management
    - management-dev.yml
    - management-prod.yml

... Você entendeu a ideia

O componente é um pouco diferente

@Component
public class PropertiesConfigurer extends     PropertySourcesPlaceholderConfigurer
    implements EnvironmentAware, InitializingBean {

private final static Logger LOG = LoggerFactory.getLogger(PropertiesConfigurer.class);

private String[] locations;

@Autowired
private ResourceLoader rl;
private Environment environment;

@Override
public void setEnvironment(Environment environment) {
    // save off Environment for later use
    this.environment = environment;
    super.setEnvironment(environment);
}

@Override
public void afterPropertiesSet() throws Exception {
    // Copy property sources to Environment
    MutablePropertySources envPropSources = ((ConfigurableEnvironment) environment).getPropertySources();
    envPropSources.forEach(propertySource -> {
        if (propertySource.containsProperty("application.properties.locations")) {
            locations = ((String) propertySource.getProperty("application.properties.locations")).split(",");
            stream(locations).forEach(filename -> loadProperties(filename).forEach(source ->{
                envPropSources.addFirst(source);
            }));
        }
    });
}


private List<PropertySource> loadProperties(final String filename) {
    YamlPropertySourceLoader loader = new YamlPropertySourceLoader();
    try {
        final Resource[] possiblePropertiesResources = ResourcePatternUtils.getResourcePatternResolver(rl).getResources(filename);
        final Properties properties = new Properties();
        return stream(possiblePropertiesResources)
                .filter(Resource::exists)
                .map(resource1 -> {
                    try {
                        return loader.load(resource1.getFilename(), resource1);
                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    }
                }).flatMap(l -> l.stream())
                .collect(Collectors.toList());
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
}

}


3

Se você deseja substituir os valores especificados no arquivo application.properties, é possível alterar o perfil ativo enquanto executa o aplicativo e criar um arquivo de propriedades do aplicativo para o perfil. Então, por exemplo, vamos especificar o perfil ativo "substituir" e, supondo que você tenha criado seu novo arquivo de propriedades do aplicativo chamado "application-override.properties" em / tmp, poderá executar

java -jar yourApp.jar --spring.profiles.active="override" --spring.config.location="file:/tmp/,classpath:/" 

Os valores especificados em spring.config.location são avaliados na ordem inversa. Portanto, no meu exemplo, o classpat é avaliado primeiro, depois o valor do arquivo.

Se o arquivo jar e o arquivo "application-override.properties" estiverem no diretório atual, você poderá simplesmente usar

java -jar yourApp.jar --spring.profiles.active="override"

desde que o Spring Boot encontre o arquivo de propriedades para você


1
Ele informará ao Spring para usar o perfil "substituir" como seu perfil ativo; Seria de fato viaduto o valor especificado no arquivo application.yml ou application.properties
acaruci

ele vai olhar dentro da pasta para qualquer .ymal arquivo de configuração ou .properties no meu caso eu colocar apenas application-profile.yml em seguida, leva corretamente, Graças @acaruci foi uma boa viagem
Ahmed Salem

0

Eu descobri que esse é um padrão útil a seguir:

@RunWith(SpringRunner)
@SpringBootTest(classes = [ TestConfiguration, MyApplication ],
        properties = [
                "spring.config.name=application-MyTest_LowerImportance,application-MyTest_MostImportant"
                ,"debug=true", "trace=true"
        ]
)

Aqui substituímos o uso de "application.yml" para usar "application-MyTest_LowerImportance.yml" e também "application-MyTest_MostImportant.yml"
(o Spring também procurará arquivos .properties)

Também estão incluídas como um bônus extra as configurações de depuração e rastreamento, em uma linha separada para que você possa comentá-las, se necessário;]

A depuração / rastreamento é incrivelmente útil, pois o Spring despeja os nomes de todos os arquivos que ele carrega e daqueles que ele tenta carregar.
Você verá linhas como esta no console em tempo de execução:

TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'file:./config/application-MyTest_MostImportant.properties' (file:./config/application-MyTest_MostImportant.properties) resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'file:./config/application-MyTest_MostImportant.xml' (file:./config/application-MyTest_MostImportant.xml) resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'file:./config/application-MyTest_MostImportant.yml' (file:./config/application-MyTest_MostImportant.yml) resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'file:./config/application-MyTest_MostImportant.yaml' (file:./config/application-MyTest_MostImportant.yaml) resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'file:./config/application-MyTest_LowerImportance.properties' (file:./config/application-MyTest_LowerImportance.properties) resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'file:./config/application-MyTest_LowerImportance.xml' (file:./config/application-MyTest_LowerImportance.xml) resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'file:./config/application-MyTest_LowerImportance.yml' (file:./config/application-MyTest_LowerImportance.yml) resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'file:./config/application-MyTest_LowerImportance.yaml' (file:./config/application-MyTest_LowerImportance.yaml) resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'file:./application-MyTest_MostImportant.properties' (file:./application-MyTest_MostImportant.properties) resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'file:./application-MyTest_MostImportant.xml' (file:./application-MyTest_MostImportant.xml) resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'file:./application-MyTest_MostImportant.yml' (file:./application-MyTest_MostImportant.yml) resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'file:./application-MyTest_MostImportant.yaml' (file:./application-MyTest_MostImportant.yaml) resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'file:./application-MyTest_LowerImportance.properties' (file:./application-MyTest_LowerImportance.properties) resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'file:./application-MyTest_LowerImportance.xml' (file:./application-MyTest_LowerImportance.xml) resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'file:./application-MyTest_LowerImportance.yml' (file:./application-MyTest_LowerImportance.yml) resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'file:./application-MyTest_LowerImportance.yaml' (file:./application-MyTest_LowerImportance.yaml) resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'classpath:/config/application-MyTest_MostImportant.properties' resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'classpath:/config/application-MyTest_MostImportant.xml' resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'classpath:/config/application-MyTest_MostImportant.yml' resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'classpath:/config/application-MyTest_MostImportant.yaml' resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'classpath:/config/application-MyTest_LowerImportance.properties' resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'classpath:/config/application-MyTest_LowerImportance.xml' resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'classpath:/config/application-MyTest_LowerImportance.yml' resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'classpath:/config/application-MyTest_LowerImportance.yaml' resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'classpath:/application-MyTest_MostImportant.properties' resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'classpath:/application-MyTest_MostImportant.xml' resource not found
DEBUG 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Loaded config file 'file:/Users/xxx/dev/myproject/target/test-classes/application-MyTest_MostImportant.yml' (classpath:/application-MyTest_MostImportant.yml)
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'classpath:/application-MyTest_MostImportant.yaml' resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'classpath:/application-MyTest_LowerImportance.properties' resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'classpath:/application-MyTest_LowerImportance.xml' resource not found
DEBUG 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Loaded config file 'file:/Users/xxx/dev/myproject/target/test-classes/application-MyTest_LowerImportance.yml' (classpath:/application-MyTest_LowerImportance.yml)
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'classpath:/application-MyTest_LowerImportance.yaml' resource not found
TRACE 93941 --- [   main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'file:./config/application-MyTest_MostImportant-test.properties' (file:./config/application-MyTest_MostImportant-test.properties) resource not found

-1

Eu tive muitos problemas ao tentar descobrir isso. Aqui está minha configuração,

Env Dev: Windows 10, Java: 1.8.0_25, Spring Boot: 2.0.3.RELEASE, Spring: 5.0.7.RELEASE

O que eu descobri é que a primavera está aderindo ao conceito "Padrões sensíveis para configuração". O que isso significa é que você precisa ter todos os seus arquivos de propriedades como parte do seu arquivo de guerra. Uma vez lá, você pode substituí-los usando a propriedade da linha de comando "--spring.config.additional-location" para apontar para arquivos de propriedades externas. Mas isso NÃO funcionará se os arquivos de propriedades não fizerem parte do arquivo de guerra original.

Código de demonstração: https://github.com/gselvara/spring-boot-property-demo/tree/master

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.