Spring Boot y múltiples archivos de configuración externos

125

Tengo varios archivos de propiedades que quiero cargar desde classpath. Hay un conjunto predeterminado en el /src/main/resourcesque forma parte myapp.jar. Mi springcontextespera que los archivos estén en el classpath. es decir

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

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

También necesito la opción de anular estas propiedades con un conjunto externo. Tengo una carpeta de configuración externa en cwd. Según la carpeta de configuración de Spring boot doc debe estar en classpath. Pero no está claro en el documento si solo anulará elapplicaiton.properties desde allí o todas las propiedades en la configuración.

Cuando lo probé, solo application.propertiesse recogen y el resto de las propiedades aún se recogen /src/main/resources. He intentado suministrarlos como una lista separada por comas aspring.config.location pero el conjunto predeterminado todavía no se anula.

¿Cómo hago que varios archivos de configuración externos anulen los predeterminados?

Como solución, actualmente utilizo app.config.location(propiedad específica de la aplicación) que proporciono a través de la línea de comando. es decir

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

y cambié mi applicationcontexta

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

Y así es como hago la separación entre el archivo y classpath al cargar la aplicación.
EDICIONES:

//psuedo code

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

Realmente me gustaría no usar la solución anterior y hacer que Spring anule todos los archivos de configuración externos en el classpath como lo hace para el application.propertiesarchivo.

nir
fuente
44
El application.propertiessiempre se cargará, con spring.config.locationusted puede agregar ubicaciones adicionales de configuración que se comprueban los archivos (que es cuando termina con una /), sin embargo si se pone una coma separados ahí que apunta a los archivos de los que se cargará. Esto también se explica en la Guía de referencia de Spring Boot aquí
M. Deinum,

Respuestas:

154

Cuando se utiliza Spring Boot, las propiedades se cargan en el siguiente orden (consulte Configuración externalizada en la guía de referencia de Spring Boot).

  1. Argumentos de línea de comando.
  2. Propiedades del sistema Java (System.getProperties ()).
  3. Variables de entorno del sistema operativo.
  4. Atributos JNDI de java: comp / env
  5. Un RandomValuePropertySource que solo tiene propiedades al azar. *.
  6. Propiedades de la aplicación fuera de su jar empaquetado (application.properties, incluidas YAML y variantes de perfil).
  7. Propiedades de la aplicación empaquetadas dentro de su jar (application.properties, incluidas YAML y variantes de perfil).
  8. Anotaciones de @PropertySource en sus clases de @Configuration.
  9. Propiedades predeterminadas (especificadas mediante SpringApplication.setDefaultProperties).

Al resolver propiedades (es decir, la @Value("${myprop}")resolución se realiza en el orden inverso (comenzando con 9).

Para agregar diferentes archivos, puede usar las spring.config.locationpropiedades que toman una lista separada por comas de archivos de propiedades o ubicación de archivos (directorios).

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

El anterior agregará un directorio que se consultará para los application.propertiesarchivos.

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

Esto agregará el archivo de 2 propiedades a los archivos que se cargan.

Los archivos y ubicaciones de configuración predeterminados se cargan antes que los especificados adicionalmente spring.config.location, lo que significa que este último siempre anulará las propiedades establecidas en los anteriores. (Consulte también esta sección de la Guía de referencia de Spring Boot).

Si spring.config.locationcontiene directorios (a diferencia de los archivos) deben terminar en / (y se agregarán con los nombres generados spring.config.nameantes de cargarse). La ruta de búsqueda predeterminada classpath:,classpath:/config,file:,file:config/siempre se usa, independientemente del valor de spring.config.location. De esa manera, puede configurar los valores predeterminados para su aplicación application.properties(o cualquier otro nombre de base que elija spring.config.name) y anularlo en tiempo de ejecución con un archivo diferente, manteniendo los valores predeterminados.

ACTUALIZACIÓN: como el comportamiento de spring.config.location ahora anula el valor predeterminado en lugar de agregarlo. Debe usar spring.config.additional-location para mantener los valores predeterminados. Este es un cambio en el comportamiento de 1.xa 2.x

M. Deinum
fuente
2
Gracias, pero ya he leído este documento de referencia y lo siguiente es confuso para mí "-Dspring.config.location = your / config / dir / El de arriba agregará un directorio que será consultado para los archivos de application.properties". ¿Qué significa los archivos application.properties? Eso es solo un archivo. En cualquier caso, si es capaz de recoger todo el directorio con "/" al final, entonces no necesito especificar cada uno como una lista separada por comas. Creo que he intentado ambos enfoques como mencioné en mi publicación, pero lo intentaré una vez más
nir
Como se indica en el documento, se consultará como las otras ubicaciones predeterminadas para application.propertiesy application-[env].properties. No tiene en cuenta otros archivos de propiedades. Esto también se indica en la guía de referencia (en la sección a la que conduce el enlace y la cita de la guía de referencia).
M. Deinum
1
Sí, pero eso es lo que no tiene sentido para mí ... ¿por qué considerar solo un tipo de archivo de un directorio en classpath en lugar de todo el directorio? Te obliga a usar un solo archivo de propiedades, lo que no es bueno. Al igual que en Tomcat, puedo configurar common.loader para poner un directorio particular (y todo lo que está dentro) en classpath, ¿por qué no puede arrancarlo?
nir
3
Citar documentación no es útil. Si la documentación fuera clara (¿suficiente? ¿De la manera particularmente necesaria?), Entonces la pregunta no sería necesaria. Por ejemplo, en este caso, realmente no está claro cómo config.locatione config.namesinteractuar, aunque probablemente parezca claro para las personas que ya saben cómo interactúan. ¿Puedes actualizar tu respuesta para agregar algo a la documentación?
Narfanator
13
Esto debe actualizarse, ya que el comportamiento de spring.config.locationahora anula el valor predeterminado en lugar de agregarlo. Debe usar spring.config.additional-locationpara mantener los valores predeterminados. Este es un cambio de comportamiento de 1.xa 2.x.
Robin
32

Con Spring boot, spring.config.location funciona, solo proporciona archivos de propiedades separados por comas.

ver el siguiente código

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

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

uno puede poner la versión predeterminada de jdbc.properties dentro de la aplicación. Las versiones externas se pueden configurar mentira esto.

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

Según el valor del perfil establecido con la propiedad spring.profiles.active, se recogerá el valor de jdbc.host. Entonces cuando (en windows)

set spring.profiles.active=dev

jdbc.host tomará valor de jdbc-dev.properties.

para

set spring.profiles.active=default

jdbc.host tomará valor de jdbc.properties.

ganesh jadhav
fuente
No creo que el primero de los bloques de código funcione. Sé que me tropecé con este, y seguí esta respuesta . Ver jira.springsource.org/browse/SPR-8539 referenciado en respuesta para una explicación decente.
Sowka
27

Spring boot 1.X y Spring Boot 2.X no proporcionan las mismas opciones y comportamiento sobre el Externalized Configuration .

La muy buena respuesta de M. Deinum se refiere a las especificaciones de Spring Boot 1.
Actualizaré para Spring Boot 2 aquí.

Fuentes de propiedades ambientales y orden

Spring Boot 2 usa un PropertySourceorden muy particular que está diseñado para permitir una anulación sensata de los valores. Las propiedades se consideran en el siguiente orden:

  • Propiedades de configuración global de Devtools en su directorio de inicio (~ / .spring-boot-devtools.properties cuando devtools está activo).

  • @TestPropertySource anotaciones en tus pruebas.

  • @SpringBootTest#propertiesatributo de anotación en sus pruebas. Argumentos de línea de comando.

  • Propiedades de SPRING_APPLICATION_JSON(JSON en línea incrustado en una variable de entorno o propiedad del sistema).

  • ServletConfig parámetros de inicio

  • ServletContext parámetros de inicio

  • Atributos JNDI de java:comp/env.

  • Propiedades del sistema Java ( System.getProperties()).

  • Variables de entorno del sistema operativo.

  • A RandomValuePropertySourceque tiene propiedades solo al azar. *.

  • Propiedades de aplicación específicas de perfil fuera de su jar empaquetado ( application-{profile}.propertiesy variantes de YAML).

  • Propiedades de aplicación específicas de perfil incluidas dentro de su jar ( application-{profile}.propertiesy variantes de YAML).

  • Propiedades de la aplicación fuera de su jar empaquetado ( application.propertiesy variantes YAML).

  • Propiedades de la aplicación empaquetadas dentro de su jar ( application.propertiesy variantes de YAML).

  • @PropertySourceanotaciones en tus @Configurationclases. Propiedades predeterminadas (especificadas por la configuración SpringApplication.setDefaultProperties).

Para especificar archivos de propiedades externas, estas opciones deberían interesarle:

  • Propiedades de aplicación específicas de perfil fuera de su jar empaquetado ( application-{profile}.propertiesy variantes de YAML).

  • Propiedades de la aplicación fuera de su jar empaquetado ( application.propertiesy variantes YAML).

  • @PropertySourceanotaciones en tus @Configurationclases. Propiedades predeterminadas (especificadas por la configuración SpringApplication.setDefaultProperties).

Puede usar solo una de estas 3 opciones o combinarlas según sus requisitos.
Por ejemplo, para casos muy simples, usar solo propiedades específicas de perfil es suficiente, pero en otros casos es posible que desee usar propiedades específicas de perfil, propiedades predeterminadas y @PropertySource.

Ubicaciones predeterminadas para los archivos application.properties

Acerca de los application.propertiesarchivos (y variantes), Spring los carga de forma predeterminada y agrega sus propiedades en el entorno a partir de estos en el siguiente orden:

  • Un subdirectorio / config del directorio actual

  • El directorio actual

  • Un paquete classpath / config

  • La raíz de classpath

Las prioridades más altas son tan literalmente:
classpath:/,classpath:/config/,file:./,file:./config/.

¿Cómo usar archivos de propiedades con nombres específicos?

Las ubicaciones predeterminadas no siempre son suficientes: las ubicaciones predeterminadas como el nombre de archivo predeterminado ( application.properties) pueden no ser adecuadas. Además, como en la pregunta de OP, es posible que deba especificar varios archivos de configuración distintos de application.properties(y variante).
Entoncesspring.config.name no será suficiente.

En este caso, debe proporcionar una ubicación explícita utilizando la spring.config.locationpropiedad del entorno (que es una lista separada por comas de ubicaciones de directorio o rutas de archivos).
Para ser libre sobre el patrón de nombres de archivo, favorezca la lista de rutas de archivos sobre la lista de directorios.
Por ejemplo hacer así:

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

Esa manera es la más detallada que solo especificando la carpeta, pero también es la forma de especificar muy finamente nuestros archivos de configuración y documentar claramente las propiedades efectivamente utilizadas.

spring.config.location ahora reemplaza las ubicaciones predeterminadas en lugar de agregarlas

Con Spring Boot 1, el spring.config.locationargumento agrega ubicaciones específicas en el entorno Spring.
Pero desde Spring Boot 2, spring.config.locationreemplaza las ubicaciones predeterminadas utilizadas por Spring por las ubicaciones especificadas en el entorno de Spring como se indica en la documentación .

Cuando las ubicaciones de configuración personalizadas se configuran mediante el uso spring.config.location, reemplazan las ubicaciones predeterminadas. Por ejemplo, si spring.config.locationse configura con el valor classpath:/custom-config/, file:./custom-config/el orden de búsqueda se convierte en la siguiente:

  1. file:./custom-config/

  2. classpath:custom-config/

spring.config.locationahora es una forma de asegurarse de que cualquier application.propertiesarchivo tenga que especificarse explícitamente.
Para los JAR súper que no deben empaquetar application.propertiesarchivos, eso es bastante bueno.

Para mantener el viejo comportamiento de spring.config.location Spring Boot 2, puede usar la nueva spring.config.additional-locationpropiedad en lugar de spring.config.locationque todavía agregue las ubicaciones como se indica en la documentación :

Alternativamente, cuando las ubicaciones de configuración personalizadas se configuran usando spring.config.additional-location, se usan además de las ubicaciones predeterminadas.


En la práctica

Supongamos que, como en la pregunta OP, tiene que especificar 2 archivos de propiedades externas y 1 archivo de propiedades incluido en el uber jar.

Para usar solo los archivos de configuración que especificó:

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

Para agregar archivos de configuración a estos en las ubicaciones predeterminadas:

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

classpath:/applications.properties en el último ejemplo no es obligatorio ya que las ubicaciones predeterminadas tienen eso y las ubicaciones predeterminadas aquí no se sobrescriben sino que se extienden.

davidxxx
fuente
Su respuesta es realmente completa, excepto en una cosa: ¿dónde encontrará Spring la configuración externa job1.properties en el disco si solo especifica: "classpath: /job1.properties"? ¿Cómo agregaste aquí tu directorio que contiene propiedades externas al classpath?
Tristán
@Tristan, básicamente, spring puede leer uno application.propertiescon todos los parámetros y múltiples ${file_name}.propertiescon conjuntos de propiedades definidos parcialmente. Por lo tanto, si usa @PropertySourceu otros enlaces fuertes a archivos, puede crear otro archivo externo y anular esas propiedades (por ejemplo: desde classpath:file.properties).
Mister_Jesus
23

Eche un vistazo al PropertyPlaceholderConfigurer, me parece más fácil de usar que la anotación.

p.ej

@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;
    }
usuario3206144
fuente
Muchas gracias por esta respuesta. ¿Puede decirme cómo puedo lograr lo mismo en un proyecto que tiene configuraciones XML similares para diferentes cosas sin un archivo XML base? Su respuesta anterior me ayudó en otro proyecto basado en anotaciones. Gracias de nuevo por eso.
Chetan
8

este es un enfoque simple usando el arranque de primavera

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;
    }
}

el contexto de app.properties , en la ubicación seleccionada

test.one = 1234

su aplicación de arranque de primavera

@SpringBootApplication

public class TestApplication {

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

y el contexto predefinido application.properties

spring.profiles.active = one

puede escribir tantas clases de configuración como desee y habilitarlas / deshabilitarlas simplemente configurando spring.profiles.active = el nombre / nombres del perfil {separados por comas}

como puede ver, el arranque de primavera es excelente, solo necesita algún tiempo para familiarizarse, vale la pena mencionar que también puede usar @Value en sus campos

@Value("${test.one}")
String str;
Farzan Skt
fuente
7

Yo tuve el mismo problema. Quería tener la capacidad de sobrescribir un archivo de configuración interna en el inicio con un archivo externo, similar a la detección de Spring Boot application.properties. En mi caso, es un archivo user.properties donde se almacenan los usuarios de mis aplicaciones.

Mis requisitos:

Cargue el archivo desde las siguientes ubicaciones (en este orden)

  1. El classpath
  2. A / config subdirectorio del directorio actual.
  3. El directorio actual
  4. Desde el directorio o una ubicación de archivo dada por un parámetro de línea de comando al inicio

Se me ocurrió la siguiente solución:

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;
    }

}

Ahora la aplicación usa el recurso classpath, pero también busca un recurso en las otras ubicaciones dadas. El último recurso que existe será elegido y utilizado. Puedo iniciar mi aplicación con java -jar myapp.jar --properties.location = / directory / myproperties.properties para usar una ubicación de propiedades que flota mi barco.

Un detalle importante aquí: utilice una cadena vacía como valor predeterminado para la ubicación de propiedades en la anotación @Value para evitar errores cuando no se establece la propiedad.

La convención para una ubicación de propiedades es: Use un directorio o una ruta a un archivo de propiedades como propiedades.ubicación.

Si desea anular solo propiedades específicas, se puede usar un PropertiesFactoryBean con setIgnoreResourceNotFound (true) con la matriz de recursos establecida como ubicaciones.

Estoy seguro de que esta solución se puede extender para manejar múltiples archivos ...

EDITAR

Aquí mi solución para múltiples archivos :) Como antes, esto se puede combinar con un 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;
    }

}
mxsb
fuente
Buena solución. Al igual que construcciones java8! de todos modos no puedo usar eso, ya que necesito múltiples propiedades de beans, no solo uno. Si ves mis EDICIONES, mi solución es bastante similar y ordenada para mi caso de uso.
nir
Publiqué una versión para varios archivos, solo para completar;)
mxsb
6

Spring Boot nos permite escribir diferentes perfiles para escribir para diferentes entornos, por ejemplo, podemos tener archivos de propiedades separados para entornos de producción, qa y locales

El archivo application-local.properties con configuraciones de acuerdo con mi máquina local es

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

Del mismo modo, podemos escribir application-prod.properties y application-qa.properties tantos archivos de propiedades como queramos

luego escriba algunos scripts para iniciar la aplicación para diferentes entornos, por ejemplo

mvn spring-boot:run -Drun.profiles=local
mvn spring-boot:run -Drun.profiles=qa
mvn spring-boot:run -Drun.profiles=prod
Monstruo humilde
fuente
5

Acabo de tener un problema similar a esto y finalmente descubrí la causa: el archivo application.properties tenía los atributos de propiedad y rwx incorrectos. Entonces, cuando Tomcat inició el archivo application.properties estaba en la ubicación correcta, pero era propiedad de otro usuario:

$ chmod 766 application.properties

$ chown tomcat application.properties
robjwilkins
fuente
Creo que tengo un problema similar. He instalado tomcat en la carpeta opt. ¿Dónde colocó su archivo de solicitud? ¿Debo cambiar los atributos de la carpeta también?
anakin59490
3

Una versión modificada de la solución @mxsb que nos permite definir múltiples archivos y en mi caso estos son archivos yml.

En mi aplicación-dev.yml, agregué esta configuración que me permite inyectar todos los yml que tienen -dev.yml en ellos. Esta puede ser una lista de archivos específicos también. "classpath: /test/test.yml,classpath: /test2/test.yml"

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

Esto ayuda a obtener un mapa de propiedades.

@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);
    }
}
}

Sin embargo, si como en mi caso, quisiera tener que dividir los archivos yml para cada perfil y cargarlos e inyectarlos directamente en la configuración del resorte antes de la inicialización de los beans.

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

... tienes la idea

El componente es ligeramente 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);
    }
}

}

Codewarrior
fuente
3

Si desea anular los valores especificados en su archivo application.properties, puede cambiar su perfil activo mientras ejecuta su aplicación y crea un archivo de propiedades de la aplicación para el perfil. Entonces, por ejemplo, especifiquemos el perfil activo "anular" y luego, suponiendo que haya creado su nuevo archivo de propiedades de la aplicación llamado "application-override.properties" en / tmp, puede ejecutar

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

Los valores especificados en spring.config.location se evalúan en orden inverso. Entonces, en mi ejemplo, primero se evalúa el classpat, luego el valor del archivo.

Si el archivo jar y el archivo "application-override.properties" están en el directorio actual, puede simplemente usar

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

ya que Spring Boot encontrará el archivo de propiedades por ti

acaruci
fuente
1
Le indicará a spring que use el perfil de "anulación" como su perfil activo; de hecho, superaría el valor especificado en el archivo application.yml o application.properties
acaruci
buscará dentro de la carpeta cualquier archivo de configuración .ymal o .properties en mi caso, puse solo application-profile.yml y luego se tomó correctamente, gracias @acaruci fue un buen viaje
Ahmed Salem
0

He encontrado que este es un patrón útil a seguir:

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

Aquí anulamos el uso de "application.yml" para usar "application-MyTest_LowerImportance.yml" y también "application-MyTest_MostImportant.yml"
(Spring también buscará archivos .properties)

También se incluye como una bonificación adicional la configuración de depuración y rastreo, en una línea separada para que pueda comentarlos si es necesario;]

La depuración / rastreo es increíblemente útil ya que Spring volcará los nombres de todos los archivos que carga y los que intenta cargar.
Verá líneas como esta en la consola en tiempo de ejecución:

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
davidfrancis
fuente
-1

Me encontré con muchos problemas al tratar de resolver esto. He aquí mi arreglo,

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

Lo que encontré es que Spring está apegado al concepto "Valores predeterminados sensibles para la configuración". Esto se traduce en que debes tener todos tus archivos de propiedad como parte de tu archivo de guerra. Una vez allí, puede anularlos utilizando la propiedad de línea de comando "--spring.config.additional-location" para apuntar a archivos de propiedades externas. Pero esto NO FUNCIONARÁ si los archivos de propiedades no son parte del archivo de guerra original.

Código de demostración: https://github.com/gselvara/spring-boot-property-demo/tree/master

gselvara
fuente