Використання змінної env у застосуванні Spring Boot.properties


200

Ми працюємо над веб-програмою Spring Boot , і база даних, яку ми використовуємо, - MySql ;

  • у нас є те, що ми спочатку перевіряємо її локально (означає, що нам потрібно встановити MySql на нашому ПК);

  • потім ми натискаємо на Bitbucket ;

  • Дженкінс автоматично виявляє новий поштовх до Bitbucket і робить його на основі (для того, щоб здати конструкцію Jenkins mvn, нам також потрібно встановити MySql на віртуальних машинах, на яких працює Дженкінс).

  • якщо пропуск Дженкінса будує, ми відсилаємо код до нашої програми на OpenShift (використовуючи плагін розгортання Openshift на Jenkins).

Проблема, яку ми маємо, як ви вже зрозуміли, полягає в тому, що:

  • в application.propertiesми не можемо важко кодувати інформацію MySql. Оскільки наш проект буде працювати в трьох різних місцях ( локальному , Jenkins та OpenShift ), нам потрібно зробити поле джерела даних динамічним application.properties(ми знаємо, що це робиться по-різному, але зараз ми працюємо над цим рішенням).

    spring.datasource.url = 
    spring.datasource.username = 
    spring.datasource.password = 

Ми придумали рішення: ми створюємо змінні системного середовища локально та в vm Jenkins (називаючи їх так само, як OpenShift називає їх) та присвоюючи їм правильні значення відповідно:

export OPENSHIFT_MYSQL_DB_HOST="jdbc:mysql://localhost"
export OPENSHIFT_MYSQL_DB_PORT="3306"
export OPENSHIFT_MYSQL_DB_USERNAME="root"
export OPENSHIFT_MYSQL_DB_PASSWORD="123asd"

Ми це зробили, і це працює. Ми також перевірили, Map<String, String> env = System.getenv();що змінні середовища можуть бути перетворені в java змінні як такі:

String password = env.get("OPENSHIFT_MYSQL_DB_PASSWORD");   
String userName = env.get("OPENSHIFT_MYSQL_DB_USERNAME");   
String sqlURL = env.get("OPENSHIFT_MYSQL_DB_HOST"); 
String sqlPort = env.get("OPENSHIFT_MYSQL_DB_PORT");

Тепер єдине, що нам залишається - нам потрібно використовувати ці змінні Java в нашому, application.propertiesі це те, з чим ми маємо проблеми.

В якій папці, і як нам потрібно призначити password, userName, sqlURLі sqlPortзмінні , application.propertiesщоб мати можливість бачити їх і як ми включаємо їх в application.properties?

Ми спробували багато речей, одна з яких:

spring.datasource.url = ${sqlURL}:${sqlPort}/"nameofDB"
spring.datasource.username = ${userName}
spring.datasource.password = ${password}

Поки не пощастило. Ми, ймовірно, не ставимо цих змінних env у потрібний клас / папку або використовуємо їх неправильно application.properties.

Ваша допомога високо цінується !!

Дякую!


3
Читайте @ConfigurationProperties, щоб дізнатися більше. Однак це ідеальний випадок використання властивостей конфігурації профілю
Едді Б

Відповіді:


270

Вам не потрібно використовувати змінні java. Щоб включити змінні системи env, додайте у application.propertiesфайл наступне :

spring.datasource.url = ${OPENSHIFT_MYSQL_DB_HOST}:${OPENSHIFT_MYSQL_DB_PORT}/"nameofDB"
spring.datasource.username = ${OPENSHIFT_MYSQL_DB_USERNAME}
spring.datasource.password = ${OPENSHIFT_MYSQL_DB_PASSWORD}

Але шлях запропонований @Stefan Isele є кращим, оскільки в цьому випадку ви повинні оголосити тільки одна змінна ENV: spring.profiles.active. Spring автоматично прочитає відповідний файл властивостей за application-{profile-name}.propertiesшаблоном.


12
Цей спосіб зручніший для з'єднання докерів. Наприклад:docker run --name my-tomcat -p 127.0.0.1:8080:8080 -e APP_DB_DB=mydb -e APP_DB_USER=dbuser -e APP_DB_PASS=dbpass --link mongo-myapp:mongo -v /path-to/tomcat/webapps:/usr/local/tomcat/webapps -d tomcat:8-jre8-alpine
Fırat KÜÇÜK

17
Це абсолютно найкращий шлях. Використання змінних оточуючих середовищ означає, що вам не потрібно перераховувати секрети у простому тексті поряд із додатком. Це значно безпечніше та зменшує залежність від заходів безпеки доступу до вихідного коду для захисту всієї власності. Випадкова публікація SO із включеними властивостями не призводить до витікання інформації.
kipper_t

51
Я хотів додати до цього і зазначити, що якщо ви використовуєте весняний завантажувач (не перевіряв, чи працює він без завантаження), будь-яке властивість може бути замінено автоматично через змінну середовища без зміни вашої application.properties. тобто, якщо у вас є властивість , spring.activemq.broker-urlто відповідна змінна оточення буде: SPRING_ACTIVEMQ_BROKER_URL. періоди та тире автоматично перетворюються на підкреслення. Це надзвичайно зручно при роботі з контейнерами / пружинним завантаженням.
абе

15
Якщо ви розробляєте хмари, це не кращий спосіб використання весняних профілів. Використовувати змінні середовища рекомендується 12-ти факторним стандартом програми: 12factor.net/config
Михайло Голубцов,

6
Я знаю, що ця тема трохи стара. Але ви можете поєднувати як налаштування змінної середовища, так і налаштування весняного профілю. У вашого профілю розробника має бути статична інформація, тоді як ваш виробничий профіль може використовувати змінні середовища. Таким чином, розробникам більше не потрібно визначати змінні середовища на своїй машині, якщо вони просто хочуть розгорнути профіль розробки.
підкреслюй_05

72

Найпростіший спосіб мати різні конфігурації для різних середовищ - це використовувати пружинні профілі. Див. Зовнішню конфігурацію .

Це дає велику гнучкість. Я використовую його у своїх проектах, і це надзвичайно корисно. У вашому випадку у вас буде 3 профілі: "локальний", "дженкінс" та "відкритий зсув"

Після цього у вас 3 профілю файли конкретних властивостей: application-local.properties, application-jenkins.propertiesіapplication-openshift.properties

Там ви можете встановити властивості щодо середовища. Під час запуску програми потрібно вказати профіль, щоб активуватись так: -Dspring.profiles.active=jenkins

Редагувати

Відповідно до весняного документа ви можете встановити змінну системного середовища SPRING_PROFILES_ACTIVEдля активації профілів і не потрібно передавати її як параметр.

чи є можливість передати активний варіант профілю для веб-додатків під час виконання?

Ні. Spring визначає активні профілі як один із перших кроків при побудові контексту програми. Активні профілі потім використовуються для визначення того, які файли властивостей читаються та які файли використовуються. Після запуску програми це неможливо змінити.


4
Мені подобається ця відповідь, але що робити, якщо ви хочете, щоб назва профілю походила з оточення? Я спробував -Dspring.active.profiles = $ SPRING_ACTIVE_PROFILES і встановив OS env var у /etc/profile.d/myenvvars.sh, але Spring Boot цього не сприймає
Том Хартвелл

1
SPRING_PROFILES_ACTIVE працює через розслаблену функцію прив’язки весняного завантаження docs.spring.io/spring-boot/docs/1.3.0.BUILD-SNAPSHOT/reference/…
feed.me

5
дякую за цю відповідь Стефан, він працював на мене, але з однією зміною - властивість насправді є spring.profiles.active, а не spring.active.profiles
Rudi,

11
Хоча пружинні профілі можуть бути дуже корисними, стосовно ОП вони не підходять. Це пов’язано з тим, як зберігається вихідний код та чутливістю інформації про властивості, що зберігається разом із цим. Контекст ОП є навколо доступу до бази даних. У цій ситуації ви не хочете деталізувати інформацію про звичайний текст у джерелі. Це означає, що якщо джерело порушено, то також буде порушена база даних. Краще використовувати для цього змінні env або секретні інструменти, такі як Vault. Я віддаю перевагу env. Я також змусив би всі середовища діяти однаково в цьому плані для послідовності. Це дозволяє уникнути нещасних випадків у майбутньому.
kipper_t

2
Ви можете використовувати файл властивостей профілю Spring Boot, що знаходиться поза програмою JAR. Наприклад, цей файл, орієнтований на середовище application-production.properties, буде захищено на виробничій машині захищеним способом, і, як правило, не буде у сховищі вихідного коду програми.
Колін Д Беннетт

13

Це є відповіддю на ряд коментарів, оскільки моя репутація недостатньо висока для прямого коментування.

Ви можете вказати профіль під час виконання, поки контекст програми ще не завантажений.

// Previous answers incorrectly used "spring.active.profiles" instead of
// "spring.profiles.active" (as noted in the comments).
// Use AbstractEnvironment.ACTIVE_PROFILES_PROPERTY_NAME to avoid this mistake.

System.setProperty(AbstractEnvironment.ACTIVE_PROFILES_PROPERTY_NAME, environment);
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("/META-INF/spring/applicationContext.xml");

12

Flayway не розпізнає змінні прямої середовища у application.properties (Spring-Boot V2.1). напр

spring.datasource.url=jdbc:mysql://${DB_HOSTNAME}:${DB_PORT}/${DB_DATABASE}
spring.datasource.username=${DB_USER}
spring.datasource.password=${DB_PASS}

Щоб вирішити цю проблему, я робив цю змінну середовища, зазвичай створюю файл .env:

SPRING_DATASOURCE_URL=jdbc:mysql://127.0.0.1:3306/place
SPRING_DATASOURCE_USERNAME=root
SPRING_DATASOURCE_PASSWORD=root

І експортувати змінні в моє середовище:

export $(cat .env | xargs)

І нарешті просто запустіть команду

mvn spring-boot:run

Або запустіть ваш jar файл

java -jar target/your-file.jar

Тут є ще один підхід: https://docs.spring.io/spring-boot/docs/2.1.0.BUILD-SNAPSHOT/maven-plugin/examples/run-env-variables.html


1
Що таке env-vars? Як вони використовуються. Ваша відповідь стосується речей без повного опису, і ви не включаєте жодних посилань. Я майже не сприйняв це, але я бачу, що у вас є представник 21, тому ви новачок, і одна людина вважає вашу відповідь корисною, тому я відпустив її, але спробуйте надати більше інформації в майбутніх відповідях, і ласкаво просимо до SO (Stack Overflow). Сподіваюся, вам сподобається так само, як і мені.
PatS

2
Дякую @PatS, я додав більше деталей, сподіваюся, що це стане в нагоді.
Феліпе

1
Відмінні зміни. Дякуємо за оновлення вашої відповіді.
PatS

9

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

Файл властивостей у ресурсах програми ( src / main / ресурси ): -

 1. application.properties
 2. application-dev.properties
 3. application-uat.properties
 4. application-prod.properties

В ідеалі, application.properties містить усі загальні властивості, доступні для всіх середовищ, а властивості, пов'язані з довкіллям, працюють лише на вказане середовище. тому порядок завантаження цих файлів властивостей буде таким чином -

 application.properties -> application.{spring.profiles.active}.properties.

Фрагмент коду тут: -

    import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
    import org.springframework.core.io.ClassPathResource;
    import org.springframework.core.io.Resource;

    public class PropertiesUtils {

        public static final String SPRING_PROFILES_ACTIVE = "spring.profiles.active";

        public static void initProperties() {
            String activeProfile = System.getProperty(SPRING_PROFILES_ACTIVE);
            if (activeProfile == null) {
                activeProfile = "dev";
            }
            PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer
                    = new PropertySourcesPlaceholderConfigurer();
            Resource[] resources = new ClassPathResource[]
                    {new ClassPathResource("application.properties"),
                            new ClassPathResource("application-" + activeProfile + ".properties")};
            propertySourcesPlaceholderConfigurer.setLocations(resources);

        }
    }

2
Хіба Spring Boot не справляється з цим сценарієм поза рамками? Дивіться документацію щодо зовнішньої конфігурації тут
ChickenFeet

4

Можливо, я пишу це занадто пізно, але я зіткнувся з подібною проблемою, коли намагався змінити методи зчитування властивостей.

Моєю проблемою було: 1) Прочитати властивість з env, якщо цю властивість було встановлено у env 2) Прочитати властивість із системної власності, якщо ця властивість була встановлена ​​у властивості системи 3) І останнє, прочитати з властивостей програми.

Отже, для вирішення цієї проблеми я переходжу до свого класу конфігурації бобів

@Validated
@Configuration
@ConfigurationProperties(prefix = ApplicationConfiguration.PREFIX)
@PropertySource(value = "${application.properties.path}", factory = PropertySourceFactoryCustom.class)
@Data // lombok
public class ApplicationConfiguration {

    static final String PREFIX = "application";

    @NotBlank
    private String keysPath;

    @NotBlank
    private String publicKeyName;

    @NotNull
    private Long tokenTimeout;

    private Boolean devMode;

    public void setKeysPath(String keysPath) {
        this.keysPath = StringUtils.cleanPath(keysPath);
    }
}

І перезаписати завод у @PropertySource. І тоді я створив власну реалізацію для властивостей читання.

    public class PropertySourceFactoryCustom implements PropertySourceFactory {

        @Override
        public PropertySource<?> createPropertySource(String name, EncodedResource resource) throws IOException {
            return name != null ? new PropertySourceCustom(name, resource) : new PropertySourceCustom(resource);
        }


    }

І створив PropertySourceCustom

public class PropertySourceCustom extends ResourcePropertySource {


    public LifeSourcePropertySource(String name, EncodedResource resource) throws IOException {
        super(name, resource);
    }

    public LifeSourcePropertySource(EncodedResource resource) throws IOException {
        super(resource);
    }

    public LifeSourcePropertySource(String name, Resource resource) throws IOException {
        super(name, resource);
    }

    public LifeSourcePropertySource(Resource resource) throws IOException {
        super(resource);
    }

    public LifeSourcePropertySource(String name, String location, ClassLoader classLoader) throws IOException {
        super(name, location, classLoader);
    }

    public LifeSourcePropertySource(String location, ClassLoader classLoader) throws IOException {
        super(location, classLoader);
    }

    public LifeSourcePropertySource(String name, String location) throws IOException {
        super(name, location);
    }

    public LifeSourcePropertySource(String location) throws IOException {
        super(location);
    }

    @Override
    public Object getProperty(String name) {

        if (StringUtils.isNotBlank(System.getenv(name)))
            return System.getenv(name);

        if (StringUtils.isNotBlank(System.getProperty(name)))
            return System.getProperty(name);

        return super.getProperty(name);
    }
}

Отже, це мені допомогло.


4

Використовуючи Spring контекст 5.0, я успішно досягнув завантаження правильного файлу властивості на основі системного середовища за допомогою наступних приміток

@PropertySources({
    @PropertySource("classpath:application.properties"),
    @PropertySource("classpath:application-${MYENV:test}.properties")})

Тут значення MYENV зчитується з системного середовища, і якщо системного середовища немає, тоді файл властивостей тестового середовища за замовчуванням буде завантажений, якщо я даю неправильне значення MYENV - воно не зможе запустити програму.

Примітка: для кожного профілю, який ви хочете підтримувати - вам потрібно буде зробити додаток [файл] .property, і хоча я використовував Spring контекст 5.0 і не Spring boot - я вважаю, що це також буде працювати на Spring 4.1


3

Я зіткнувся з тим же питанням, що і автор запитання. Для нашого випадку відповідей на це запитання було недостатньо, оскільки кожен з членів моєї команди мав інше місцеве середовище, і нам, безумовно, потрібен .gitignoreфайл, який відрізнявся db-рядком з'єднання і обліковими даними, тому люди не вводять загальний файл помилково і розірвати db-з'єднання інших.

На додаток до цього, коли ми дотримувались наведеної нижче процедури, було легко розгортатися в різних середовищах, і як додатковий бонус нам взагалі не потрібно було містити конфіденційну інформацію в контролі версій .

Отримавши ідею з PHP Symfony 3 parameters.ymlфрейму, що має (.gitignored) та a parameters.yml.dist(що є зразком, який створює перший наскрізь composer install),

Я зробив наступне, поєднуючи знання з відповідей нижче: https://stackoverflow.com/a/35534970/986160 та https://stackoverflow.com/a/35535138/986160 .

По суті, це дає свободу використовувати успадкування пружинних конфігурацій та вибирати активні профілі через конфігурацію у верхній частині плюс будь-які додаткові чутливі облікові дані:

application.yml.dist (зразок)

    spring:
      profiles:
        active: local/dev/prod
      datasource:
        username:
        password:
        url: jdbc:mysql://localhost:3306/db?useSSL=false&useLegacyDatetimeCode=false&serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8

application.yml (.gitignore-d на сервері розробників)

spring:
  profiles:
    active: dev
  datasource:
    username: root
    password: verysecretpassword
    url: jdbc:mysql://localhost:3306/real_db?useSSL=false&useLegacyDatetimeCode=false&serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8

application.yml (.gitignore-d на локальній машині)

spring:
  profiles:
    active: dev
  datasource:
    username: root
    password: rootroot
    url: jdbc:mysql://localhost:3306/xampp_db?useSSL=false&useLegacyDatetimeCode=false&serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8

application-dev.yml (додаткові специфічні властивості середовища не чутливі)

spring:
  datasource:
    testWhileIdle: true
    validationQuery: SELECT 1
  jpa:
    show-sql: true
    format-sql: true
    hibernate:
      ddl-auto: create-droop
      naming-strategy: org.hibernate.cfg.ImprovedNamingStrategy
    properties:
      hibernate:
        dialect: org.hibernate.dialect.MySQL57InnoDBDialect

Те ж саме можна зробити і з. Властивостями


0

Якщо файли властивостей зовнішні як змінні середовища, наступна конфігурація запуску може бути додана в IDE:

--spring.config.additional-location={PATH_OF_EXTERNAL_PROP}

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.