Spring Boot'un uygulamasında env değişkenini kullanma. Properties


200

Bir Spring Boot web uygulaması üzerinde çalışıyoruz ve kullandığımız veritabanı MySql ;

  • Sahip olduğumuz kurulum ilk olarak test etmemiz yerel olarak etmemizdir (PC'ye MySql yüklememiz gerektiği anlamına gelir);

  • sonra iteriz Bitbucket'e geçiyoruz ;

  • Jenkins otomatik olarak Bitbucket'e yeni bir itme algılar ve üzerinde bir yapı oluşturur (Jenkins mvn derlemesinin geçmesi için MySql'i Jenkins çalıştıran sanal makinelere de yüklememiz gerekir).

  • Jenkins derleme geçerse kodu OpenShift'teki uygulamamıza aktarırız (Jenkins üzerindeki Openhift dağıtım eklentisini kullanarak).

Sahip olduğumuz problem önce çözmüş olabileceğiniz gibi :

  • içinde application.propertiesMySql bilgilerini kodlayamıyoruz. Projemiz 3 farklı yerde ( yerel , Jenkins ve OpenShift ) çalışacağından , veri kaynağı alanını dinamik hale getirmeliyiz application.properties(bunu yapmanın farklı yolları olduğunu biliyoruz, ancak şimdilik bu çözüm üzerinde çalışıyoruz).

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

Ortaya koyduğumuz çözüm, sistem ortamı değişkenlerini yerel olarak ve Jenkins vm'de (bunları OpenShift ile aynı şekilde adlandırır) ve sırasıyla doğru değerleri atamamızdır:

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"

Bunu yaptık ve işe yarıyor. Ayrıca Map<String, String> env = System.getenv();, ortam değişkenlerinin java değişkenlerine dönüştürülebildiğini kontrol ettik :

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

Şimdi geriye kalan tek şey bu java değişkenlerini application.properties ve sorunumuz da budur.

Hangi klasörde ve nasıl, biz atamak gerekiyor password, userName, sqlURL, ve sqlPortiçin değişkenler application.propertiesonları görmek mümkün ve biz onları nasıl eklerimapplication.properties ?

Bunlardan biri olan birçok şeyi denedik:

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

Şimdiye kadar şans yok. Muhtemelen bu env değişkenlerini doğru sınıfa / klasöre koymuyoruz ya da yanlış kullanıyoruz application.properties.

Yardımlarınız çok takdir !!

Teşekkürler!


3
Daha fazla bilgi için @ConfigurationProperties sayfasını okuyun . Bununla birlikte, bu,
Eddie B 2

Yanıtlar:


270

Java değişkenleri kullanmanıza gerek yoktur. Sistem env değişkenlerini eklemek için application.propertiesdosyanıza aşağıdakileri ekleyin :

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}

Ama önerdiği yolu @Stefan Isele bu durumda sadece tek env değişken bildirmek zorunda çünkü, daha tercih edilir: spring.profiles.active. Spring, uygun özellik dosyasını application-{profile-name}.propertiesşablonla otomatik olarak okuyacaktır .


12
Bu yöntem liman işçisi bağlantı için daha uygundur. Örneğin: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
Bu kesinlikle gitmek için en iyi yoldur. Ortam değişkenlerini kullanmak, sırları uygulamanızın yanı sıra düz metin olarak listelemeniz gerekmediği anlamına gelir. Bu önemli ölçüde daha güvenlidir ve tüm mülkünüzü korumak için kaynak kodu erişim güvenlik önlemlerinize olan bağımlılığı azaltır. Özelliklerin dahil olduğu bir kazara SO gönderisi, bilgilerin dışarı sızmasına neden olmaz.
kipper_t

51
Buna eklemek ve bahar önyükleme kullanıyorsanız (önyükleme olmadan çalışıp çalışmadığını kontrol etmediyseniz), herhangi bir özelliğin, application.properties'i değiştirmeden otomatik olarak bir ortam değişkeni ile geçersiz kılınabileceğini belirtmek istedim. Eğer adlı bir özellik varsa, yani spring.activemq.broker-urldaha sonra ilgili ortam değişkeni olacaktır: SPRING_ACTIVEMQ_BROKER_URL. nokta ve kısa çizgiler otomatik olarak alt çizgilere dönüştürülür. Kaplar / yaylı bot ile çalışırken bu son derece kullanışlıdır.
abe

15
Bulut için tasarlarsanız, Spring profillerini kullanmak tercih edilen bir yol değildir. 12 faktörlü uygulama standardı tarafından ortam değişkenlerinin kullanılması önerilir: 12factor.net/config
Mikhail Golubtsov

6
Bu konunun biraz eski olduğunu biliyorum. Ancak, hem ortam değişkeni kurulumunu hem de yay profili kurulumunu birleştirebilirsiniz. Üretim profiliniz ortam değişkenlerini kullanabilirken geliştirme profilinizde statik bilgiler olmalıdır. Bu şekilde geliştiricilerin artık geliştirme profilini dağıtmak istiyorlarsa makinelerinde ortam değişkenlerini tanımlamasına gerek kalmaz.
underscore_05

72

Farklı ortamlar için farklı konfigürasyonlara sahip olmanın en kolay yolu yay profilleri kullanmaktır. Harici yapılandırmaya bakın .

Bu size çok fazla esneklik sağlar. Projelerimde kullanıyorum ve son derece yararlı. Sizin durumunuzda 3 profiliniz olacaktır: 'yerel', 'jenkins' ve 'openshift'

Daha sonra 3 profil özgü özellik dosyaları var: application-local.properties, application-jenkins.properties, veapplication-openshift.properties

Burada ilgili ortamın özelliklerini ayarlayabilirsiniz. Uygulamayı çalıştırdığınızda, etkinleştirilecek profili şu şekilde belirtmeniz gerekir: -Dspring.profiles.active=jenkins

Düzenle

Spring doc'a göre, SPRING_PROFILES_ACTIVEprofilleri etkinleştirmek için sistem ortamı değişkenini ayarlayabilirsiniz ve parametre olarak iletmeniz gerekmez.

Web uygulaması için etkin profil seçeneğini çalışma zamanında geçirmenin bir yolu var mı?

Hayır. Spring, uygulama içeriğini oluştururken etkin profilleri ilk adımlardan biri olarak belirler. Aktif profiller daha sonra hangi özellik dosyalarının okunduğuna ve hangi çekirdeklerin başlatıldığına karar vermek için kullanılır. Uygulama başlatıldıktan sonra bu değiştirilemez.


4
Bu yanıtı beğendim, ancak profil adının çevreden gelmesini isterseniz ne olur? -Dspring.active.profiles = $ SPRING_ACTIVE_PROFILES'i denedim ve OS env ayarını /etc/profile.d/myenvvars.sh içinde ayarladım, ancak Spring Boot bunu almıyor
Tom Hartwell

1
SPRING_PROFILES_ACTIVE, bahar önyüklemesinin rahat bağlama özelliği nedeniyle çalışır docs.spring.io/spring-boot/docs/1.3.0.BUILD-SNAPSHOT/reference/…
feed.me

5
Bu cevap için teşekkürler Stefan, benim için çalıştı, ama bir değişiklikle - mülkiyet aslında spring.profiles.active ve spring.active.profiles
Rudi

11
Spring profilleri çok faydalı olsa da, OP ile ilgili olarak uygun değildirler. Bunun nedeni, kaynak kodun nasıl saklandığı ve bununla birlikte saklanan özellikler bilgilerinin hassasiyetidir. OP içeriği Veritabanı erişimi etrafındadır. Bu durumda, kaynaktaki düz metinde ürün ayrıntıları istemezsiniz. Bu, eğer kaynak tehlikeye atılırsa veritabanı da tehlikeye atılır. Bunun için Apps Kasası gibi env değişkenlerini veya gizli araçları kullanmak daha iyidir. Ben env. Ayrıca tutarlılık açısından tüm ortamların aynı şekilde çalışmasını sağlarım. Gelecekte kazaları önler.
kipper_t

2
JAR uygulamasının dışındaki bir Spring Boot profil özellikleri dosyası kullanabilirsiniz. Örneğin, bu ortama özgü dosya application-production.propertiesüretim makinesine güvenli bir şekilde dağıtılacak ve genellikle uygulama kaynak kodu deposunda bulunmayacaktır.
Colin D Bennett

13

İtibarım doğrudan yorum yapmak için yeterince yüksek olmadığından, bu bir dizi yoruma yanıt veriyor.

Uygulama bağlamı henüz yüklenmediği sürece profili çalışma zamanında belirtebilirsiniz.

// 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) içindeki doğrudan ortam değişkenlerini tanımıyor . Örneğin

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

Bu sorunu çözmek için bu ortam değişkenlerini yaptım, genellikle .env dosyasını oluşturuyorum:

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

Ve değişkenleri çevreme aktar:

export $(cat .env | xargs)

Ve son olarak sadece komutu çalıştırın

mvn spring-boot:run

Veya jar dosyanızı çalıştırın

java -jar target/your-file.jar

Burada başka bir yaklaşım var: https://docs.spring.io/spring-boot/docs/2.1.0.BUILD-SNAPSHOT/maven-plugin/examples/run-env-variables.html


1
Env-vars nedir? Nasıl kullanılırlar. Cevabınız, tam bir açıklaması olmayan şeyleri ifade eder ve herhangi bir bağlantı eklemezsiniz. Bunu neredeyse reddediyorum, ancak temsilcinizin 21 olduğunu görüyorum, bu yüzden yeni ve bir kişi cevabınızı yararlı buldum, bu yüzden bıraktım, ancak gelecekteki cevaplarda daha fazla bilgi sağlamaya çalışın ve SO'ya (Stack Overflow) hoş geldiniz. Umarım benim kadar eğlenirsiniz.
PatS

2
Teşekkürler @PatS, daha fazla ayrıntı ekledim, umarım faydalı olacaktır.
Felipe Girotti

1
Mükemmel değişiklikler. Cevabınızı güncellediğiniz için teşekkür ederiz.
PatS

9

Buraya , farklı ortamlar için yüklenen bir ortamlar zinciri özellikleri parçacığı kodu bulunmaktadır.

Uygulama kaynaklarınızın altındaki özellikler dosyası ( src / main / resources ): -

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

İdeal olarak, application.properties tüm ortamlar için erişilebilir olan tüm ortak özellikleri içerir ve çevreyle ilgili özellikler yalnızca belirli ortamlarda çalışır. bu nedenle bu özellik dosyalarını yükleme sırası bu şekilde olacaktır -

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

Kod pasajı buraya: -

    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 bu senaryoyu kutudan çıkarmıyor mu? Buradan Harici Yapılandırma belgelerine
ChickenFeet

4

Belki bunu çok geç yazıyorum, ancak özellikleri okuma yöntemlerini geçersiz kılmaya çalıştığımda benzer bir sorun var.

Benim sorunum: 1) Bu özellik env olarak ayarlanmışsa env özelliklerinden okuma 2) Bu özellik sistem özelliklerinde ayarlanmışsa sistem özelliklerinden özellik okuma 3) Ve son olarak, uygulama özelliklerinden okuma.

Bu sorunu çözmek için fasulye konfigürasyon sınıfıma gidiyorum

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

Ve @PropertySource'daki fabrikanın üzerine yaz. Ve sonra özellikleri okumak için kendi uygulamamı oluşturdum.

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


    }

Ve oluşturulan 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);
    }
}

Bu bana yardımcı oldu.


4

Spring bağlamı 5.0'ı kullanarak, aşağıdaki notla sistem ortamına dayalı doğru özellik dosyasını yüklemeyi başarıyla sağladım

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

Burada MYENV değeri sistem ortamından okunur ve sistem ortamı mevcut değilse, varsayılan test ortamı özellik dosyası yüklenir, yanlış bir MYENV değeri verirseniz - uygulamayı başlatamaz.

Not: her profil için, korumak istediğiniz - bir uygulama yapmanız gerekir- [profil] .property dosyası ve Bahar bağlamı değil Bahar bağlamı 5.0 kullanmış olsam da - bunun Bahar 4.1'de de çalışacağına inanıyorum


3

Sorunun yazarı ile aynı sorunla karşılaştım. Bizim durumumuza göre, ekibimin her üyesinin farklı bir yerel ortamı olduğundan ve .gitignorefarklı db bağlantı dizesi ve kimlik bilgilerine sahip dosyaya kesinlikle ihtiyaç duyduğumuz için bu sorudaki cevaplar yeterli değildi , bu yüzden insanlar ortak dosyayı taahhüt etmiyorlar yanlışlıkla ve başkalarının db bağlantılarını koparmak.

Bunun da ötesinde, aşağıdaki prosedürü izlediğimizde farklı ortamlara yerleştirmek kolaydı ve ekstra bonus olarak sürüm kontrolünde herhangi bir hassas bilgiye ihtiyacımız olmadı .

Bir parameters.yml(.gitignored) ve bir parameters.yml.dist(ilkini oluşturan bir örnek olan ) PHP Symfony 3 çerçevesinden fikir edinmekcomposer install ,

Aşağıdaki cevaplardan gelen bilgileri birleştirerek aşağıdakileri yaptım: https://stackoverflow.com/a/35534970/986160 ve https://stackoverflow.com/a/35535138/986160 .

Esasen bu , yay konfigürasyonlarının mirasını kullanma ve en üstteki konfigürasyon ve aşağıdaki gibi ekstra hassas kimlik bilgileri yoluyla aktif profilleri seçme özgürlüğü verir :

application.yml.dist (örnek)

    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 (dev sunucusunda .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 (yerel makinede .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 (çevreye özgü ekstra özelliklere duyarlı değil)

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

Aynısı .properties ile yapılabilir


0

Özellik dosyaları, ortam yapılandırması olarak dışsallaştırılmışsa, aşağıdaki yapılandırma IDE'ye eklenebilir:

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

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.