Spring Boot i wiele zewnętrznych plików konfiguracyjnych

126

Mam wiele plików właściwości, które chcę załadować ze ścieżki klas. Istnieje jeden domyślny zestaw, do /src/main/resourcesktórego należy myapp.jar. Moje springcontextpliki oczekuje się na ścieżce klasy. to znaczy

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

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

Potrzebuję również opcji zastąpienia tych właściwości zewnętrznym zestawem. Mam zewnętrzny folder konfiguracyjny w cwd. Jak na wiosnę, folder konfiguracyjny boot doc powinien znajdować się w ścieżce klasy. Ale z dokumentu nie wynika jasno, czy zastąpi on tylko applicaiton.propertiesstamtąd lub wszystkie właściwości w config.

Kiedy go testowałem, tylko application.propertiessą odbierane, a pozostałe nieruchomości są nadal odbierane /src/main/resources. Próbowałem podać je jako listę oddzieloną przecinkami, spring.config.locationale domyślny zestaw nadal nie jest zastępowany.

Jak sprawić, by wiele zewnętrznych plików konfiguracyjnych zastąpiło domyślne?

Obecnie używałem app.config.location(właściwość specyficzna dla aplikacji) jako obejście tego problemu, którą dostarczam za pomocą wiersza poleceń. to znaczy

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

i zmieniłem applicationcontextna

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

I tak robię separację pomiędzy plikiem a ścieżką klas podczas ładowania aplikacji.
EDYCJE:

//psuedo code

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

Naprawdę nie chciałbym używać powyższego obejścia i sprawić, by sprężyna nadpisała wszystkie zewnętrzne pliki konfiguracyjne w ścieżce klas, tak jak ma to miejsce w przypadku application.propertiespliku.

nir
źródło
4
application.propertiesZawsze będzie załadowany, ze spring.config.locationmożna dodać dodatkowe lokalizacje konfiguracyjnych, które są zaznaczone pliki (czyli gdy kończy się /), jednakże jeśli umieścisz oddzielone przecinkami listę tam co wskazuje na pliki te zostaną załadowane. Jest to również wyjaśnione w przewodniku Spring Boot Reference tutaj
M. Deinum

Odpowiedzi:

157

Podczas korzystania z rozruchu sprężynowego właściwości są ładowane w następującej kolejności (patrz Konfiguracja zewnętrzna w przewodniku po rozruchu sprężynowym).

  1. Argumenty wiersza poleceń.
  2. Właściwości systemu Java (System.getProperties ()).
  3. Zmienne środowiskowe systemu operacyjnego.
  4. Atrybuty JNDI z java: comp / env
  5. RandomValuePropertySource, który ma tylko właściwości losowe. *.
  6. Właściwości aplikacji poza spakowanym plikiem jar (application.properties, w tym YAML i warianty profilu).
  7. Właściwości aplikacji spakowane w Twoim pliku jar (application.properties, w tym YAML i warianty profilu).
  8. @PropertySource adnotacje na Twoich klasach @Configuration.
  9. Właściwości domyślne (określone za pomocą SpringApplication.setDefaultProperties).

Podczas rozwiązywania właściwości (np @Value("${myprop}") Rozdzielanie odbywa się w odwrotnej kolejności (czyli zaczynając od 9).

Aby dodać różne pliki, możesz użyć spring.config.locationwłaściwości, które przyjmują rozdzieloną przecinkami listę plików właściwości lub lokalizację pliku (katalogi).

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

Ten powyżej doda katalog, w którym będą sprawdzane application.propertiespliki.

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

Spowoduje to dodanie 2 plików właściwości do ładowanych plików.

Domyślne pliki konfiguracyjne i lokalizacje są ładowane przed dodatkowymi określonymi plikami spring.config.location, co oznacza, że ​​te ostatnie zawsze zastępują właściwości ustawione we wcześniejszych. (Zobacz także tę sekcję Przewodnika po sprężynach rozruchowych).

Jeśli spring.config.locationzawiera katalogi (w przeciwieństwie do plików), powinny kończyć się na / (i zostaną uzupełnione nazwami wygenerowanymi spring.config.nameprzed załadowaniem). Domyślna ścieżka wyszukiwania classpath:,classpath:/config,file:,file:config/jest zawsze używana, niezależnie od wartości spring.config.location. W ten sposób możesz ustawić domyślne wartości dla swojej aplikacji w application.properties(lub jakiejkolwiek innej bazie, którą wybierzesz spring.config.name) i nadpisać je w czasie wykonywania innym plikiem, zachowując wartości domyślne.

AKTUALIZACJA: Ponieważ zachowanie spring.config.location teraz zastępuje domyślne, zamiast je dodawać. Aby zachować wartości domyślne, musisz użyć spring.config.additional-location. To jest zmiana w zachowaniu z 1.x na 2.x

M. Deinum
źródło
2
Dzięki, ale przeczytałem już ten dokument referencyjny i następujące po nim są dla mnie mylące "-Dspring.config.location = twój / config / dir / Powyższy plik doda katalog, w którym będą sprawdzane pliki application.properties." Co to oznacza przez pliki application.properties. To tylko jeden plik. W każdym razie, jeśli jest w stanie pobrać cały katalog z "/" na końcu, nie muszę określać każdego jako listy oddzielonej przecinkami. Myślę, że próbowałem obu podejść, jak wspomniałem w moim poście, ale spróbuję jeszcze raz
nir
Jak stwierdzono w dokumencie, zostanie on wybrany, podobnie jak inne domyślne lokalizacje dla application.propertiesi application-[env].properties. Nie uwzględnia innych plików właściwości. Jest to również określone w przewodniku referencyjnym (w sekcji, do której prowadzi łącze, oraz cytacie z przewodnika).
M. Deinum,
1
Tak, ale to nie ma dla mnie sensu… dlaczego rozważać tylko jeden rodzaj pliku z katalogu na ścieżce klas zamiast z całego katalogu. Zmusza cię do używania tylko jednego pliku właściwości, co nie jest dobrym imo. Podobnie jak w tomcat, mogę skonfigurować common.loader tak, aby umieścić określony katalog (i wszystko w nim zawarte) w ścieżce klasy, dlaczego nie można uruchomić modułu ładującego klasy, aby go obsłużyć.
nir
3
Cytowanie dokumentacji nie jest pomocne. Gdyby dokumentacja była jasna (wystarczająco? W szczególnie potrzebny sposób?), To pytanie nie byłoby konieczne. Na przykład w tym przypadku naprawdę nie jest jasne, w jaki sposób config.locationi config.namesinterakcji, chociaż prawdopodobnie wydaje się to jasne dla osób, które już wiedzą, jak wchodzą w interakcje. Czy możesz zaktualizować swoją odpowiedź, aby dodać coś do dokumentacji?
Narfanator
13
Powinno to zostać zaktualizowane, ponieważ zachowanie spring.config.locationteraz zastępuje domyślne, zamiast dodawać do niego. Musisz użyć, spring.config.additional-locationaby zachować wartości domyślne. To jest zmiana w zachowaniu z 1.x na 2.x.
Robin
32

W przypadku rozruchu Spring, spring.config.location działa, wystarczy dostarczyć pliki właściwości oddzielone przecinkami.

zobacz poniższy kod

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

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

w aplikacji można umieścić domyślną wersję jdbc.properties. Wersje zewnętrzne można ustawić w ten sposób.

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

Na podstawie wartości profilu ustawionej za pomocą właściwości spring.profiles.active zostanie pobrana wartość jdbc.host. Więc kiedy (w systemie Windows)

set spring.profiles.active=dev

jdbc.host przyjmie wartość z jdbc-dev.properties.

dla

set spring.profiles.active=default

jdbc.host przyjmie wartość z jdbc.properties.

ganesh jadhav
źródło
Nie wierzę, że pierwszy z bloków kodu zadziała. Wiem, gdy zgarnąłem się na tym i podążyłem za tą odpowiedzią . Zobacz jira.springsource.org/browse/SPR-8539, do którego odwołuje się w odpowiedzi, aby uzyskać przyzwoite wyjaśnienie.
Sowka
27

Spring boot 1.X i Spring Boot 2.X nie zapewniają tych samych opcji i zachowania w przypadku Externalized Configuration.

Bardzo dobra odpowiedź M. Deinum odnosi się do specyfiki Spring Boot 1.
Zaktualizuję tutaj Spring Boot 2.

Źródła i porządek właściwości środowiska

Spring Boot 2 używa bardzo szczególnej PropertySourcekolejności, która umożliwia rozsądne zastępowanie wartości. Właściwości są rozpatrywane w następującej kolejności:

  • Właściwości globalnych ustawień Devtools w katalogu domowym (~ / .spring-boot-devtools.properties, gdy devtools jest aktywne).

  • @TestPropertySource adnotacje na temat twoich testów.

  • @SpringBootTest#propertiesatrybut adnotacji w twoich testach. Argumenty wiersza poleceń.

  • Właściwości z SPRING_APPLICATION_JSON(wbudowane JSON osadzone w zmiennej środowiskowej lub właściwości systemowej).

  • ServletConfig parametry init.

  • ServletContext parametry init.

  • Atrybuty JNDI z java:comp/env.

  • Właściwości systemu Java ( System.getProperties()).

  • Zmienne środowiskowe systemu operacyjnego.

  • A, RandomValuePropertySourcektóry ma właściwości tylko losowo. *.

  • Właściwości aplikacji specyficzne dla profilu poza opakowanym słoikiem ( application-{profile}.propertiesi warianty YAML).

  • Właściwości aplikacji specyficzne dla profilu spakowane w Twoim słoiku ( application-{profile}.propertiesi warianty YAML).

  • Właściwości aplikacji poza opakowanym słoikiem ( application.propertiesi warianty YAML).

  • Właściwości aplikacji zapakowane w słoiku ( application.propertiesi warianty YAML).

  • @PropertySourceadnotacje na Twoich @Configurationzajęciach. Właściwości domyślne (określone przez ustawienie SpringApplication.setDefaultProperties).

Aby określić zewnętrzne pliki właściwości, te opcje powinny Cię zainteresować:

  • Właściwości aplikacji specyficzne dla profilu poza opakowanym słoikiem ( application-{profile}.propertiesi warianty YAML).

  • Właściwości aplikacji poza opakowanym słoikiem ( application.propertiesi warianty YAML).

  • @PropertySourceadnotacje na Twoich @Configurationzajęciach. Właściwości domyślne (określone przez ustawienie SpringApplication.setDefaultProperties).

Możesz użyć tylko jednej z tych 3 opcji lub połączyć je zgodnie z własnymi wymaganiami.
Na przykład w bardzo prostych przypadkach wystarczy użyć tylko właściwości specyficznych dla profilu, ale w innych przypadkach możesz chcieć użyć zarówno właściwości specyficznych dla profilu, właściwości domyślnych i @PropertySource.

Domyślne lokalizacje plików application.properties

O application.propertiesplikach (i wariantach), domyślnie Spring ładuje je i dodaje ich właściwości w środowisku z nich w następującej kolejności:

  • Podkatalog / config bieżącego katalogu

  • Bieżący katalog

  • Pakiet classpath / config

  • Katalog główny ścieżki klas

Wyższe priorytety są więc dosłownie:
classpath:/,classpath:/config/,file:./,file:./config/.

Jak używać plików właściwości o określonych nazwach?

Domyślne lokalizacje nie zawsze są wystarczające: domyślne lokalizacje, takie jak domyślna nazwa pliku ( application.properties), mogą nie pasować. Poza tym, podobnie jak w przypadku pytania OP, może być konieczne określenie wielu plików konfiguracyjnych innych niż application.properties(i wariant).
Więcspring.config.name to nie wystarczy.

W takim przypadku należy podać jawną lokalizację przy użyciu spring.config.locationwłaściwości environment (czyli rozdzielonej przecinkami listy lokalizacji katalogów lub ścieżek plików).
Aby być wolnym w kwestii wzorców nazw plików, przedkładaj listę ścieżek plików nad listę katalogów.
Na przykład zrób tak:

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

W ten sposób jest to najbardziej rozwlekłe określenie folderu, ale jest to również sposób bardzo dokładnego określenia naszych plików konfiguracyjnych i jasnego udokumentowania efektywnie używanych właściwości.

spring.config.location zastępuje teraz domyślne lokalizacje zamiast je dodawać

W przypadku Spring Boot 1 spring.config.locationargument dodaje określone lokalizacje w środowisku Spring.
Ale z Spring Boot 2, spring.config.locationzastępuje domyślne lokalizacje używane przez Spring przez określone lokalizacje w środowisku Spring, zgodnie z dokumentacją .

Gdy niestandardowe lokalizacje konfiguracji są konfigurowane przy użyciu spring.config.location, zastępują domyślne lokalizacje. Na przykład, jeśli spring.config.locationskonfigurowano z wartością classpath:/custom-config/, file:./custom-config/kolejność wyszukiwania będzie następująca:

  1. file:./custom-config/

  2. classpath:custom-config/

spring.config.locationjest teraz sposobem na upewnienie się, że każdy application.propertiesplik musi być jawnie określony.
Dla plików JAR Uber, które nie powinny być pakowaneapplication.properties plików plików, jest to raczej miłe.

Aby zachować stare zachowanie spring.config.locationpodczas korzystania z Spring Boot 2, możesz użyć nowej spring.config.additional-locationwłaściwości zamiast spring.config.locationnadal dodawać lokalizacje zgodnie z dokumentacją :

Alternatywnie, gdy niestandardowe lokalizacje konfiguracji są konfigurowane przy użyciu spring.config.additional-location, są one używane oprócz lokalizacji domyślnych.


W praktyce

Załóżmy więc, że tak jak w przypadku pytania OP, masz 2 zewnętrzne pliki właściwości do określenia i 1 plik właściwości zawarty w pliku uber jar.

Aby używać tylko określonych plików konfiguracyjnych:

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

Aby dodać do nich pliki konfiguracyjne w domyślnych lokalizacjach:

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

classpath:/applications.properties w ostatnim przykładzie nie jest wymagane, ponieważ domyślne lokalizacje to mają i te domyślne lokalizacje nie są tutaj nadpisywane, ale rozszerzane.

davidxxx
źródło
Twoja odpowiedź jest naprawdę kompletna, z wyjątkiem jednej rzeczy: gdzie Spring znajdzie na dysku zewnętrzną konfigurację job1.properties, jeśli podasz tylko: "classpath: /job1.properties"? Jak dodałeś katalog zawierający zewnętrzne właściwości do ścieżki klas tutaj?
Tristan
@Tristan, w zasadzie, sprężyna może odczytać jeden application.propertiesze wszystkimi parametrami i wiele ${file_name}.propertiesz częściowo zdefiniowanymi zestawami właściwości. Tak więc, jeśli używasz @PropertySourcelub innych silnych linków do plików, możesz utworzyć inny plik zewnętrzny i nadpisać te właściwości (na przykład: from classpath:file.properties).
Mister_Jesus
23

Spójrz na PropertyPlaceholderConfigurer, uważam, że jest jaśniejszy w użyciu niż adnotacja.

na przykład

@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
źródło
Bardzo dziękuję za tę odpowiedź. Czy możesz dać mi znać, jak mogę osiągnąć to samo w projekcie, który ma podobne konfiguracje XML dla różnych rzeczy bez podstawowego pliku XML? Twoja odpowiedź powyżej pomogła mi w innym projekcie, który był oparty na adnotacjach. Jeszcze raz dziękuję za to.
Chetan
8

jest to jedno proste podejście z użyciem butów sprężynowych

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 kontekst, w wybranej lokalizacji

test.one = 1234

Twoja aplikacja do rozruchu wiosennego

@SpringBootApplication

public class TestApplication {

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

i predefiniowany kontekst application.properties

spring.profiles.active = one

możesz napisać dowolną liczbę klas konfiguracyjnych i włączać / wyłączać je po prostu ustawiając spring.profiles.active = nazwę / nazwy profilu {oddzielone przecinkami}

jak widać, wiosenny but jest świetny, wystarczy go trochę zaznajomić, warto wspomnieć, że możesz użyć @Value również na swoich polach

@Value("${test.one}")
String str;
Farzan Skt
źródło
7

Miałem ten sam problem. Chciałem mieć możliwość nadpisania wewnętrznego pliku konfiguracyjnego podczas uruchamiania zewnętrznym plikiem, podobnie jak w przypadku wykrywania Spring Boot application.properties. W moim przypadku jest to plik user.properties, w którym znajdują się użytkownicy moich aplikacji.

Moje wymagania:

Załaduj plik z następujących lokalizacji (w tej kolejności)

  1. Ścieżka klas
  2. / Config podkatalog bieżącego katalogu.
  3. Bieżący katalog
  4. Z katalogu lub lokalizacji pliku podanej przez parametr wiersza polecenia podczas uruchamiania

Wymyśliłem następujące rozwiązanie:

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

}

Teraz aplikacja korzysta z zasobu classpath, ale sprawdza również zasób w innych podanych lokalizacjach. Ostatni istniejący zasób zostanie pobrany i użyty. Mogę uruchomić moją aplikację za pomocą java -jar myapp.jar --properties.location = / directory / myproperties.properties, aby użyć lokalizacji właściwości, która unosi moją łódź.

Ważny szczegół tutaj: Użyj pustego ciągu jako wartości domyślnej właściwości properties.location w adnotacji @Value, aby uniknąć błędów, gdy właściwość nie jest ustawiona.

Konwencja dla properties.location jest następująca: Użyj katalogu lub ścieżki do pliku właściwości jako properties.location.

Jeśli chcesz przesłonić tylko określone właściwości, można użyć PropertiesFactoryBean z setIgnoreResourceNotFound (true) z tablicą zasobów ustawioną jako lokalizacje.

Jestem pewien, że to rozwiązanie można rozszerzyć o obsługę wielu plików ...

EDYTOWAĆ

Tutaj moje rozwiązanie dla wielu plików :) Tak jak poprzednio, można to połączyć z 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
źródło
niezłe obejście. Jak te konstrukcje java8! w każdym razie nie mogę tego użyć, ponieważ potrzebuję wielu fasoli Właściwości, a nie tylko jednej. Jeśli widzisz moje EDYCJE, moje obejście jest dość podobne i zgrabne dla mojego przypadku użycia.
nir
Opublikowałem wersję dla wielu plików, tylko dla kompletności;)
mxsb
6

Spring boot pozwala nam pisać różne profile do pisania dla różnych środowisk, na przykład możemy mieć oddzielne pliki właściwości dla środowisk produkcyjnych, QA i lokalnych

plik application-local.properties z konfiguracjami zgodnymi z moim lokalnym komputerem to

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

Podobnie możemy napisać application-prod.properties i application-qa.properties tyle plików właściwości, ile chcemy

następnie napisz skrypty uruchamiające aplikację w różnych środowiskach, np

mvn spring-boot:run -Drun.profiles=local
mvn spring-boot:run -Drun.profiles=qa
mvn spring-boot:run -Drun.profiles=prod
Humble Freak
źródło
5

Właśnie miałem podobny problem i w końcu znalazłem przyczynę: plik application.properties miał niewłaściwe atrybuty własności i rwx. Więc kiedy tomcat uruchomił plik application.properties znajdował się we właściwej lokalizacji, ale należał do innego użytkownika:

$ chmod 766 application.properties

$ chown tomcat application.properties
robjwilkins
źródło
Myślę, że mam podobny problem. Zainstalowałem tomcat w folderze opt. Gdzie umieściłeś plik aplikacji? Czy powinienem też zmienić atrybuty folderów?
anakin59490
3

Zmodyfikowana wersja rozwiązania @mxsb pozwalająca na definiowanie wielu plików, w moim przypadku są to pliki yml.

W mojej aplikacji-dev.yml dodałem tę konfigurację, która pozwala mi wstrzyknąć wszystkie yml, które mają w sobie -dev.yml. Może to być również lista określonych plików. „ścieżka_klasy: /test/test.yml, ścieżka_klasy: /test2/test.yml”

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

Pomaga to uzyskać mapę właściwości.

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

Jeśli jednak tak jak w moim przypadku chciałem podzielić pliki yml dla każdego profilu, załadować je i wstrzyknąć bezpośrednio do konfiguracji sprężyn przed inicjalizacją fasoli.

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

... Masz pomysł

Komponent jest nieco inny

@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
źródło
3

Jeśli chcesz przesłonić wartości określone w pliku application.properties, możesz zmienić aktywny profil podczas uruchamiania aplikacji i utworzyć plik właściwości aplikacji dla profilu. Na przykład określmy „przesłonięcie” aktywnego profilu, a następnie, zakładając, że utworzyłeś nowy plik właściwości aplikacji o nazwie „application-override.properties” w katalogu / tmp, możesz uruchomić

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

Wartości określone w spring.config.location są oceniane w odwrotnej kolejności. Tak więc w moim przykładzie obszar klasy jest oceniany jako pierwszy, a następnie wartość pliku.

Jeśli plik jar i plik „application-override.properties” znajdują się w bieżącym katalogu, możesz po prostu użyć

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

ponieważ Spring Boot znajdzie dla Ciebie plik właściwości

acaruci
źródło
1
Poinstruuje Spring, aby używał profilu „zastąp” jako aktywnego profilu; rzeczywiście
przekroczyłby
będzie szukał w folderze dowolnego pliku konfiguracyjnego .ymal lub .properties w moim przypadku umieściłem tylko application-profile.yml, wtedy trwa to poprawnie, Dzięki @acaruci to była fajna podróż
Ahmed Salem
0

Uważam, że jest to przydatny wzór do naśladowania:

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

Tutaj zastępujemy użycie „application.yml”, aby użyć „application-MyTest_LowerImportance.yml”, a także „application-MyTest_MostImportant.yml”
(Spring będzie również szukał plików .properties)

Dodatkową korzyścią są również ustawienia debugowania i śledzenia w osobnej linii, dzięki czemu można je w razie potrzeby zakomentować;]

Debug / trace są niezwykle przydatne, ponieważ Spring zrzuca nazwy wszystkich ładowanych plików i tych, które próbuje załadować.
W konsoli w czasie wykonywania zobaczysz takie linie:

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
źródło
-1

Kiedy próbowałem to rozgryźć, napotkałem wiele problemów. Oto moja konfiguracja,

Wersja deweloperska: Windows 10, Java: 1.8.0_25, Spring Boot: 2.0.3.RELEASE, Spring: 5.0.7.RELEASE

Odkryłem, że wiosna trzyma się koncepcji „Rozsądne wartości domyślne konfiguracji”. Oznacza to, że musisz mieć wszystkie swoje pliki własności jako część pliku wojny. Tam możesz je zastąpić, używając właściwości wiersza polecenia „--spring.config.additional-location”, aby wskazać zewnętrzne pliki właściwości. Ale to NIE DZIAŁA, jeśli pliki właściwości nie są częścią oryginalnego pliku wojny.

Kod demonstracyjny: https://github.com/gselvara/spring-boot-property-demo/tree/master

gselvara
źródło