Подтвердить что ты не робот

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

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

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

Как сделать mulitiple внешние файлы конфигурации переопределить стандартные?

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

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

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

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

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

//psuedo code

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

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

4b9b3361

Ответ 1

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

  1. Аргументы командной строки.
  2. Свойства системы Java (System.getProperties()).
  3. Переменные среды ОС.
  4. Атрибуты JNDI из Java: comp/env
  5. RandomValuePropertySource, который имеет свойства только в случайном порядке. *.
  6. Свойства приложения вне вашего упакованного фляги (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.name) и переопределить его во время выполнения другим файлом, сохраняя значения по умолчанию.

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

Ответ 2

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

Ответ 3

Взгляните на 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;
    }

Ответ 4

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  • Пакет classpath/config

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

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

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

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

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

Ответ 5

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

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

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

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

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

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

}

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

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

Соглашение для свойства .location: Используйте каталог или путь к файлу свойств как property.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;
    }

}

Ответ 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

Ответ 7

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

$ chmod 766 application.properties

$ chown tomcat application.properties

Ответ 8

это простой подход с использованием spring boot

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

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

@SpringBootApplication

public class TestApplication {

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

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

spring.profiles.active = one

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

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

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

Ответ 9

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

@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

Ответ 10

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

В моем приложении -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 перед инициализацией bean-компонентов.

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

}

Ответ 11

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

Ответ 12

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

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

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

Демонстрационный код: https://github.com/gselvara/spring-boot-property-demo/tree/master