Spring Boot и несколько внешних файлов конфигурации

У меня есть несколько файлов свойств, которые я хочу загрузить из пути к классам. В /src/main/resources установлен один параметр по умолчанию, который является частью myapp.jar. Мой springcontext ожидает, что файлы будут в пути к классам. т.е.

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

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

Мне также нужна возможность переопределить эти свойства внешним набором. У меня есть внешняя папка конфигурации в cwd. В соответствии с папкой конфигурации Spring boot doc должна находиться в пути к классам. Но из документа не ясно, переопределит ли он только applicaiton.properties оттуда или все свойства в config.

Когда я его протестировал, было обнаружено только application.properties, а остальные свойства все еще были взяты из /src/main/resources. Я попытался предоставить их в виде списка, разделенного запятыми, для spring.config.location, но набор по умолчанию все еще не отменяется.

Как сделать так, чтобы несколько внешних файлов конфигурации переопределяли файлы по умолчанию?

В качестве обходного пути я в настоящее время использовал app.config.location (свойство, специфичное для приложения), которое я предоставляю через командную строку. т.е.

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

и я изменил свой applicationcontext на

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

And this is how I make separation between file and classpath while loading Application.
EDITS:

//psuedo code

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

Я действительно хотел бы не использовать вышеуказанный обходной путь и иметь Spring переопределить все внешние файлы конфигурации в пути к классам, как это делается для файла application.properties.


person nir    schedule 15.09.2014    source источник
comment
application.properties всегда будет загружаться, с spring.config.location вы можете добавить дополнительные местоположения конфигурации, которые проверяются на наличие файлов (то есть, когда он заканчивается на /), однако если вы поместите туда разделенный запятыми список, указывающий на файлы, которые будут загружены. Это также объясняется в Справочном руководстве по загрузке Spring здесь   -  person M. Deinum    schedule 16.09.2014


Ответы (12)


ОБНОВЛЕНИЕ: теперь поведение spring.config.location переопределяет значение по умолчанию, а не добавляется к нему. Вам необходимо использовать spring.config.additional-location, чтобы сохранить значения по умолчанию. Это изменение поведения с 1.x на 2.x


При использовании Spring Boot свойства загружаются в следующем порядке (см. Внешняя конфигурация в справочном руководстве по загрузке Spring).

  1. Аргументы командной строки.
  2. Свойства системы Java (System.getProperties ()).
  3. Переменные среды ОС.
  4. Атрибуты JNDI из java: comp / env
  5. RandomValuePropertySource, который имеет только случайные свойства. *.
  6. Свойства приложения за пределами вашего упакованного jar-файла (application.properties, включая YAML и варианты профиля).
  7. Свойства приложения, упакованные внутри вашего jar-файла (application.properties, включая YAML и варианты профиля).
  8. Аннотации @PropertySource в ваших классах @Configuration.
  9. Свойства по умолчанию (указываются с помощью SpringApplication.setDefaultProperties).

При разрешении свойств (т.е. @Value("${myprop}") разрешение выполняется в обратном порядке (так, начиная с 9).

Чтобы добавить разные файлы, вы можете использовать spring.config.location свойства, которые принимают список файлов свойств, разделенных запятыми, или расположение файла (каталоги).

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

Вышеупомянутый добавит каталог, в котором будут запрашиваться application.properties файлы.

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

Это добавит 2 файла свойств к загружаемым файлам.

Файлы конфигурации и местоположения по умолчанию загружаются раньше, чем spring.config.location, указанные дополнительно, что означает, что последние всегда переопределяют свойства, установленные в более ранних. (См. Также этот раздел Справочного руководства по загрузке Spring).

Если spring.config.location содержит каталоги (в отличие от файлов), они должны заканчиваться на / (и к ним будут добавлены имена, сгенерированные из spring.config.name перед загрузкой). Путь поиска по умолчанию classpath:,classpath:/config,file:,file:config/ используется всегда, независимо от значения spring.config.location. Таким образом, вы можете установить значения по умолчанию для своего приложения в application.properties (или любое другое базовое имя, которое вы выберете с помощью spring.config.name) и переопределить его во время выполнения другим файлом, сохранив значения по умолчанию.

person M. Deinum    schedule 16.09.2014
comment
Спасибо, но я уже прочитал этот справочный документ, и следующее меня сбивает с толку -Dspring.config.location = your / config / dir / Тот, что выше, добавит каталог, в котором будут проводиться консультации для файлов application.properties. Что это значит под файлами application.properties. Это только один файл. В любом случае, если он может выбрать весь каталог с помощью / в конце, мне не нужно указывать каждый в виде списка, разделенного запятыми. Я думаю, что пробовал оба подхода, как упоминал в своем сообщении, но я попробую еще раз. - person nir; 16.09.2014
comment
Как указано в документе, он будет выбран, как и другие местоположения по умолчанию для application.properties и application-[env].properties. Не учитываются другие файлы свойств. Об этом также говорится в справочнике (в разделе, на который ведет ссылка, и цитате из справочника). - person M. Deinum; 17.09.2014
comment
Да, но это то, что для меня не имеет смысла ... зачем рассматривать только один вид файла из каталога в пути к классам, а не весь каталог. Это заставляет вас использовать только один файл свойств, что, по-моему, не очень хорошо. Как и в tomcat, я могу настроить common.loader, чтобы поместить конкретный каталог (и все, что в нем) в путь к классам, почему загрузчик классов не может его поддерживать. - person nir; 18.09.2014
comment
Потому что именно так ребята из Spring Boot заставили это работать. Если вам нужно что-то еще, используйте список файлов, разделенных запятыми. Или укажите другое имя (вы также можете изменить имя по умолчанию application, если хотите). Кроме того, вы всегда можете использовать аннотацию @PropertySource для самостоятельной загрузки файлов свойств. - person M. Deinum; 18.09.2014
comment
Это решило мою проблему после 4 часов поиска, почему мой кот иногда импортировал application.yml, а иногда нет: If spring.config.location contains directories (as opposed to files) they should end in / (and will be appended with the names generated from spring.config.name before being loaded). - person eav; 10.05.2017
comment
Цитирование документации бесполезно. Если бы документация была ясной (достаточной? Особенно нужным образом?), То вопрос не возникал бы. Например, в этом случае действительно непонятно, как взаимодействуют config.location и config.names, хотя, вероятно, это кажется ясным для людей, которые уже знают, как они взаимодействуют. Можете ли вы обновить свой ответ, чтобы добавить что-нибудь в документацию? - person Narfanator; 28.02.2018
comment
Это должно быть обновлено, поскольку поведение spring.config.location теперь переопределяет значение по умолчанию, а не добавляется к нему. Вам нужно использовать spring.config.additional-location, чтобы сохранить значения по умолчанию. Это изменение поведения с 1.x на 2.x. - person Robin; 20.04.2018
comment
Как я могу получить значение с помощью $ {myprop} для любой конфигурации уровня контроллера? - person Aakash Patel; 08.10.2020

При загрузке Spring Spring.config.location действительно работает, просто укажите файлы свойств, разделенные запятыми.

см. приведенный ниже код

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

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

можно поместить в приложение версию jdbc.properties по умолчанию. На этом можно установить внешние версии.

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

На основе значения профиля, установленного с помощью свойства spring.profiles.active, будет выбрано значение jdbc.host. Итак, когда (в окнах)

set spring.profiles.active=dev

jdbc.host будет принимать значение из jdbc-dev.properties.

для

set spring.profiles.active=default

jdbc.host будет принимать значение из jdbc.properties.

person ganesh jadhav    schedule 16.05.2016
comment
Я не верю, что первый из блоков кода сработает. Я знаю, как я накололся на это и следил за этим ответ. См. Ссылку на jira.springsource.org/browse/SPR-8539 в ответе для достойного объяснения. . - person Sowka; 25.11.2018

Spring boot 1.X и Spring Boot 2.X не предоставляют одинаковые параметры и поведение для _ 1_.

Очень хороший ответ М. Дейнума относится к особенностям Spring Boot 1.
Я обновлю для Spring Boot 2 здесь.

Источники и порядок свойств среды

Spring Boot 2 использует очень специфический порядок PropertySource, который разработан, чтобы позволить разумное переопределение значений. Свойства рассматриваются в следующем порядке:

  • Свойства глобальных настроек Devtools в вашем домашнем каталоге (~ / .spring-boot-devtools.properties, когда devtools активен).

  • @TestPropertySource аннотации к вашим тестам.

  • @SpringBootTest#properties атрибут аннотации в ваших тестах. Аргументы командной строки.

  • Свойства из SPRING_APPLICATION_JSON (встроенный JSON, встроенный в переменную среды или системное свойство).

  • ServletConfig параметры инициализации.

  • ServletContext параметры инициализации.

  • Атрибуты JNDI из java:comp/env.

  • Свойства системы Java (System.getProperties()).

  • Переменные среды ОС.

  • RandomValuePropertySource, который имеет свойства только в случайном порядке. *.

  • Свойства приложения, зависящие от профиля, за пределами вашего упакованного jar-файла (варианты application-{profile}.properties и YAML).

  • Зависящие от профиля свойства приложения, упакованные внутри вашего jar-файла (варианты application-{profile}.properties и YAML).

  • Свойства приложения за пределами вашего упакованного jar-файла (варианты application.properties и YAML).

  • Свойства приложения, упакованные внутри вашего jar-файла (варианты application.properties и YAML).

  • @PropertySource аннотаций к вашим @Configuration классам. Свойства по умолчанию (задаются установкой SpringApplication.setDefaultProperties).

Чтобы указать файлы внешних свойств, вас должны заинтересовать следующие параметры:

  • Свойства приложения, зависящие от профиля, за пределами вашего упакованного jar-файла (варианты application-{profile}.properties и YAML).

  • Свойства приложения за пределами вашего упакованного jar-файла (варианты application.properties и YAML).

  • @PropertySource аннотаций к вашим @Configuration классам. Свойства по умолчанию (задаются установкой SpringApplication.setDefaultProperties).

Вы можете использовать только один из этих трех вариантов или комбинировать их в соответствии с вашими требованиями.
Например, для очень простых случаев достаточно использовать только свойства, зависящие от профиля, но в других случаях вы можете использовать оба свойства, зависящие от профиля, по умолчанию свойства и @PropertySource.

Расположение файлов application.properties по умолчанию

Что касается application.properties файлов (и вариантов), Spring по умолчанию загружает их и добавляет их свойства в среду из них в следующем порядке:

  • Подкаталог / config текущего каталога

  • Текущий каталог

  • Пакет classpath / config

  • Корень пути к классам

Высшие приоритеты буквально означают:
classpath:/,classpath:/config/,file:./,file:./config/.

Как использовать файлы свойств с определенными именами?

Ячейки по умолчанию не всегда достаточно: местоположения по умолчанию, такие как имя файла по умолчанию (application.properties), могут не подходить. Кроме того, как и в вопросе OP, вам может потребоваться указать несколько файлов конфигурации, кроме application.properties (и варианта).
Таким образом, spring.config.name будет недостаточно.

В этом случае вы должны указать точное местоположение с помощью свойства среды spring.config.location (которое представляет собой список местоположений каталогов или путей к файлам, разделенных запятыми).
Чтобы быть свободным в отношении шаблона имен файлов, предпочитайте список путей к файлам над списком каталогов.
Например, вот так:

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

Это самый подробный способ указания папки, но это также способ очень точно указать наши файлы конфигурации и четко задокументировать эффективно используемые свойства.

spring.config.location теперь заменяет местоположения по умолчанию, а не добавляет к ним

В Spring Boot 1 аргумент spring.config.location добавляет указанные местоположения в среде Spring.
Но начиная с Spring Boot 2, spring.config.location заменяет местоположения по умолчанию, используемые Spring указанными местоположениями в среде Spring, как указано в документации.

Когда пользовательские расположения конфигурации настроены с использованием spring.config.location, они заменяют расположения по умолчанию. Например, если spring.config.location настроен со значением _35 _, _ 36_, порядок поиска будет следующим:

  1. file:./custom-config/

  2. classpath:custom-config/

spring.config.location - теперь способ убедиться, что любой application.properties файл должен быть явно указан.
Для uber JAR, которые не должны упаковывать application.properties файлы, это довольно удобно.

Чтобы сохранить старое поведение spring.config.location при использовании Spring Boot 2, вы можете использовать новое свойство spring.config.additional-location вместо spring.config.location, которое по-прежнему добавляет местоположения , как указано в документации:

В качестве альтернативы, когда пользовательские расположения конфигурации настраиваются с помощью spring.config.additional-location, они используются в дополнение к расположениям по умолчанию.


На практике

Итак, предположим, что, как и в вопросе OP, у вас есть 2 файла внешних свойств, которые нужно указать, и 1 файл свойств, включенный в uber jar.

Чтобы использовать только указанные вами файлы конфигурации:

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

Чтобы добавить файлы конфигурации к ним в расположение по умолчанию:

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

classpath:/applications.properties в последнем примере не требуется, поскольку он есть в местоположениях по умолчанию, и эти местоположения по умолчанию здесь не перезаписываются, а расширяются.

person davidxxx    schedule 17.08.2018
comment
Ваш ответ действительно полный, за исключением одного: где Spring найдет на диске внешнюю конфигурацию job1.properties, если вы просто укажете: classpath: /job1.properties? Как вы добавили сюда свой каталог, содержащий внешние свойства, в путь к классам? - person Tristan; 19.05.2020
comment
@Tristan, по сути, spring может читать один application.properties со всеми параметрами и несколько ${file_name}.properties с частично определенными наборами свойств. Итак, если вы используете @PropertySource или другие надежные ссылки на файлы, вы можете создать другой внешний файл и переопределить эти свойства (например, из classpath:file.properties). - person Mister_Jesus; 06.07.2020

Взгляните на PropertyPlaceholderConfigurer, я считаю, что его проще использовать, чем аннотацию.

e.g.

@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;
    }
person user3206144    schedule 17.09.2014
comment
Большое спасибо за этот ответ. Не могли бы вы сообщить мне, как я могу добиться того же в проекте, который имеет подобные XML-конфигурации для разных вещей без базового XML-файла? Ваш ответ выше помог мне в другом проекте, основанном на аннотациях. Еще раз спасибо за это. - person Chetan; 17.01.2019
comment
Самый простой способ добиться разделения свойств. Спасибо - person Poli; 18.05.2021

это один простой подход с использованием пружинной загрузки

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

контекст app.properties в выбранном местоположении

test.one = 1234

ваше приложение для весенней загрузки

@SpringBootApplication

public class TestApplication {

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

и предопределенный контекст application.properties

spring.profiles.active = one

вы можете написать столько классов конфигурации, сколько захотите, и включить / отключить их, просто установив spring.profiles.active = имя / имена профиля {разделенные запятыми}

поскольку вы можете видеть, что весенняя загрузка - это здорово, просто нужно время, чтобы познакомиться, стоит упомянуть, что вы также можете использовать @Value в своих полях

@Value("${test.one}")
String str;
person Farzan Skt    schedule 27.04.2016

У меня такая же проблема. Я хотел иметь возможность перезаписывать внутренний файл конфигурации при запуске внешним файлом, как при обнаружении Spring Boot application.properties. В моем случае это файл user.properties, в котором хранятся пользователи моих приложений.

Мои требования:

Загрузите файл из следующих мест (в этом порядке)

  1. Путь к классам
  2. Подкаталог / config текущего каталога.
  3. Текущий каталог
  4. Из каталога или расположения файла, заданного параметром командной строки при запуске

Я пришел к следующему решению:

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

}

Теперь приложение использует ресурс пути к классам, но также проверяет наличие ресурса в других заданных местах. Будет выбран и использован последний существующий ресурс. Я могу запустить свое приложение с помощью java -jar myapp.jar --properties.location = / directory / myproperties.properties, чтобы использовать местоположение свойств, в котором плавает моя лодка.

Важная деталь: используйте пустую строку в качестве значения по умолчанию для свойства .location в аннотации @Value, чтобы избежать ошибок, когда свойство не установлено.

Соглашение для properties.location следующее: используйте каталог или путь к файлу свойств как properties.location.

Если вы хотите переопределить только определенные свойства, можно использовать PropertiesFactoryBean с setIgnoreResourceNotFound (true) с массивом ресурсов, установленным в качестве местоположений.

Я уверен, что это решение можно расширить для обработки нескольких файлов ...

ИЗМЕНИТЬ

Вот мое решение для нескольких файлов :) Как и раньше, это можно комбинировать с 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;
    }

}
person mxsb    schedule 13.03.2015
comment
хороший обходной путь. Как эта конструкция java8! в любом случае я не могу использовать это, поскольку мне нужно несколько компонентов свойств, а не только один. Если вы видите мои РЕДАКТИРОВАНИЯ, мой способ обхода очень похож и удобен для моего варианта использования. - person nir; 14.03.2015
comment
Я выложил версию для нескольких файлов, просто для полноты;) - person mxsb; 14.03.2015

Spring boot позволяет нам писать разные профили для записи для разных сред, например, у нас могут быть отдельные файлы свойств для производственных, qa и локальных сред

application-local.properties файл с конфигурациями в соответствии с моей локальной машиной

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

Точно так же мы можем написать application-prod.properties и application-qa.properties столько файлов свойств, сколько захотим.

затем напишите несколько сценариев для запуска приложения для разных сред, например

mvn spring-boot:run -Drun.profiles=local
mvn spring-boot:run -Drun.profiles=qa
mvn spring-boot:run -Drun.profiles=prod
person Humble Freak    schedule 02.11.2017

У меня только что была похожая проблема, и я, наконец, выяснил причину: файл application.properties имел неправильное владение и атрибуты rwx. Итак, когда tomcat запустил файл application.properties, он находился в нужном месте, но принадлежал другому пользователю:

$ chmod 766 application.properties

$ chown tomcat application.properties
person robjwilkins    schedule 19.02.2015
comment
Думаю, у меня похожая проблема. Я установил tomcat в папку opt. Куда вы поместили свой файл заявки? Следует ли мне также изменить атрибуты папки? - person anakin59490; 28.03.2019

Модифицированная версия решения @mxsb, которая позволяет нам определять несколько файлов, и в моем случае это файлы yml.

В моем application-dev.yml я добавил эту конфигурацию, которая позволяет мне вводить все yml, в которых есть -dev.yml. Это также может быть список определенных файлов. "путь к классам: /test/test.yml, путь к классам: /test2/test.yml"

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

Это помогает получить карту свойств.

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

Однако, как и в моем случае, я хотел разделить файлы yml для каждого профиля, загрузить их и ввести их непосредственно в конфигурацию Spring перед инициализацией beans.

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

... вы поняли

Компонент немного другой

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

}

person Codewarrior    schedule 18.08.2018

Если вы хотите переопределить значения, указанные в файле application.properties, вы можете изменить свой активный профиль во время запуска приложения и создать файл свойств приложения для профиля. Так, например, давайте укажем активный профиль «override», а затем, предполагая, что вы создали свой новый файл свойств приложения с именем «application-override.properties» в / tmp, вы можете запустить

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

Значения, указанные в spring.config.location, оцениваются в обратном порядке. Итак, в моем примере сначала оценивается classpat, а затем значение файла.

Если файл jar и файл application-override.properties находятся в текущем каталоге, вы можете просто использовать

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

поскольку Spring Boot найдет файл свойств для вас

person acaruci    schedule 12.12.2018
comment
Он скажет Spring использовать профиль переопределения в качестве активного профиля; он действительно превысит значение, указанное в файле application.yml или application.properties - person acaruci; 15.02.2019
comment
он будет искать в папке любой файл конфигурации .ymal или .properties, в моем случае я помещаю только application-profile.yml, тогда он принимает правильно, Спасибо @acaruci, это была хорошая поездка - person Ahmed Salem; 08.07.2020

Я обнаружил, что это полезный образец для подражания:

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

Здесь мы отменяем использование «application.yml» для использования «application-MyTest_LowerImportance.yml», а также «application-MyTest_MostImportant.yml»
(Spring также будет искать файлы .properties)

Также в качестве дополнительного бонуса включены настройки отладки и трассировки в отдельной строке, так что вы можете закомментировать их при необходимости;]

Отладка / трассировка невероятно полезны, поскольку Spring будет сбрасывать имена всех файлов, которые он загружает, и тех, которые он пытается загрузить.
Вы увидите такие строки в консоли во время выполнения:

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
person davidfrancis    schedule 08.03.2018

Я столкнулся с множеством проблем, пытаясь понять это. Вот моя установка,

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

Я обнаружил, что spring придерживается концепции «Разумные настройки по умолчанию для конфигурации». Это означает, что у вас должны быть все ваши файлы свойств как часть вашего военного файла. Оказавшись там, вы можете переопределить их, используя свойство командной строки "--spring.config.additional-location", чтобы указать на внешние файлы свойств. Но это НЕ РАБОТАЕТ, если файлы свойств не являются частью исходного файла war.

Демо-код: https://github.com/gselvara/spring-boot-property-demo/tree/master

person gselvara    schedule 27.08.2018