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

126

У меня есть несколько файлов свойств, которые я хочу загрузить из пути к классам. Есть один набор по умолчанию, /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. Согласно весенней папке конфигурации загрузочного документа должна быть в пути к классам. Но из документа не ясно, будет ли он отменять только 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>

И вот как я разделяю файл и путь к классам при загрузке приложения.
правок:

//psuedo code

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

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

NIR
источник
4
Они application.propertiesвсегда будут загружаться, и spring.config.locationвы можете добавить дополнительные местоположения конфигурации, которые проверяются на наличие файлов (то есть, когда он заканчивается на a /), однако, если вы поместите туда список, разделенный запятыми, который указывает на файлы, которые будут загружены. Это также объясняется в Справочном руководстве по Spring Boot здесь
М. Дейнум

Ответы:

157

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

  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 Boot).

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

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

М. Дейнум
источник
2
Спасибо, но я уже прочитал этот справочный документ, и следующее меня сбивает с толку: «-Dspring.config.location = your / config / dir / Тот, что выше, добавит каталог, в котором будут проводиться консультации для файлов application.properties». Что означает файлы application.properties. Это только один файл. В любом случае, если он может выбрать весь каталог с "/" в конце, мне не нужно указывать каждый как список, разделенный запятыми. Думаю, я пробовал оба подхода, о которых упоминал в своем сообщении, но я попробую еще раз
nir
Как указано в документе, он будет выбран, как и другие местоположения по умолчанию для application.propertiesи application-[env].properties. Не учитываются другие файлы свойств. Об этом также говорится в справочнике (в разделе, на который ведет ссылка, и цитате из справочника).
M. Deinum
1
Да, но это то, что для меня не имеет смысла ... зачем рассматривать только один вид файла из каталога в пути к классам, а не весь каталог. Это заставляет вас использовать только один файл свойств, что не очень хорошо. Как и в tomcat, я могу настроить common.loader, чтобы поместить конкретный каталог (и все, что в нем) в путь к классам, почему загрузчик классов не может его поддерживать.
nir
3
Цитирование документации бесполезно. Если бы документация была ясной (достаточной? Особенно нужным образом?), Тогда вопрос не возникал бы. Например, в этом случае действительно непонятно, как config.locationи как config.namesвзаимодействовать, хотя, вероятно, кажется понятным людям, которые уже знают, как они взаимодействуют. Можете ли вы обновить свой ответ, чтобы добавить что-нибудь в документацию?
Нарфанатор
13
Это должно быть обновлено, так как поведение spring.config.locationnow переопределяет значение по умолчанию, а не добавляется к нему. Вам нужно использовать, spring.config.additional-locationчтобы сохранить значения по умолчанию. Это изменение поведения с 1.x на 2.x.
Робин
32

При загрузке 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.

Ганеш Джадхав
источник
Я не верю, что первый из блоков кода сработает. Я знаю, как я наткнулся на это и последовал этому ответу . См. Jira.springsource.org/browse/SPR-8539, указанный в ответе, для достойного объяснения.
Sowka
27

Spring boot 1.X и Spring Boot 2.X не предоставляют те же параметры и поведение, что и Externalized Configuration.

Очень хороший ответ М. Дейнума относится к особенностям 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).

Вы можете использовать только один из этих 3 вариантов или комбинировать их в соответствии с вашими требованиями.
Например, для очень простых случаев достаточно использовать только свойства, специфичные для профиля, но в других случаях вы можете использовать как свойства, специфичные для профиля, свойства по умолчанию и @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сконфигурирован со значением classpath:/custom-config/, file:./custom-config/порядок поиска становится следующим:

  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 в последнем примере не требуется, поскольку он есть в расположениях по умолчанию, и эти расположения по умолчанию здесь не перезаписываются, а расширяются.

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

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

например

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

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

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;
Farzan Skt
источник
7

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

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

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

  1. Путь к классам
  2. / Конфигурации подкаталог текущего каталога.
  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;
    }

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

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
Скромный урод
источник
5

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

$ chmod 766 application.properties

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

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

В моем application-dev.yml я добавил эту конфигурацию, которая позволяет мне вводить все yml, в которых есть -dev.yml. Это также может быть список определенных файлов. "Путь к классам: /test/test.yml,classpath: /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);
    }
}

}

Codewarrior
источник
3

Если вы хотите переопределить значения, указанные в файле 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 найдет для вас файл свойств

acaruci
источник
1
Он скажет Spring использовать профиль «override» в качестве активного профиля; он действительно
превысит
он будет искать в папке любой конфигурационный файл .ymal или .properties. В моем случае я помещаю только application-profile.yml, тогда все работает правильно. Спасибо @acaruci, это была хорошая поездка
Ахмед Салем,
0

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

@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
davidfrancis
источник
-1

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

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

gselvara
источник