2014-06-27 14 views
10

Mi piacerebbe molto utilizzare la configurazione YAML per Spring Boot, in quanto trovo abbastanza leggibile e utile avere un singolo file che mostra quali proprietà sono attive nei miei diversi profili. Sfortunatamente, sto trovando che le proprietà di impostazione in application.yml possono essere piuttosto fragili.Come registrare la configurazione attiva in un'applicazione Spring Boot?

Cose come l'utilizzo di una tabulazione al posto di spazi causano la non esistenza di proprietà (senza avvisi a mio avviso), e troppo spesso scopro che i miei profili attivi non vengono impostati, a causa di qualche problema sconosciuto con il mio YAML.

Quindi mi chiedevo se ci sono dei ganci che mi permettano di ottenere i profili e le proprietà attualmente attivi, in modo che potessi registrarli.

Analogamente, esiste un modo per causare un errore all'avvio se lo application.yml contiene errori? O questo o un mezzo per me per convalidare lo YAML da solo, in modo che potessi uccidere il processo di avvio.

risposta

4

Ho avuto lo stesso problema, e vorrei che ci fosse un indicatore di debug che avrebbe detto al sistema di elaborazione del profilo di sputare alcune registrazioni utili. Un modo possibile per farlo sarebbe registrare un listener di eventi per il contesto dell'applicazione e stampare i profili dall'ambiente. Non ho provato a farlo in questo modo me stesso, quindi il tuo chilometraggio può variare. Penso che forse qualcosa di simile a ciò che è descritto qui:

How to add a hook to the application context initialization event?

Poi si farebbe qualcosa di simile nel vostro ascoltatore:

System.out.println("Active profiles: " + Arrays.toString(ctxt.getEnvironment().getActiveProfiles())); 

potrebbe essere la pena di provare. Un altro modo in cui potresti probabilmente farlo sarebbe dichiarare l'ambiente da iniettare nel codice in cui devi stampare i profili. Cioè .:

@Component 
public class SomeClass { 
    @Autowired 
    private Environment env; 
    ... 
    private void dumpProfiles() { 
    // Print whatever needed from env here 
    } 
} 
+0

ho adottato l'approccio di registrare i risultati del 'getEnvironment() getActiveProfiles()', come parte della registrazione all'avvio nel mio metodo 'main' dell'applicazione. – Steve

2

Se application.yml contiene errori, si verificherà un errore all'avvio. Suppongo che dipenda da cosa intendi per "errore". Certamente fallirà se lo YAML non è ben formato. Inoltre, se si imposta @ConfigurationProperties contrassegnati come ignoreInvalidFields=true, ad esempio, o se si imposta un valore che non può essere convertito. Questa è una vasta gamma di errori.

I profili attivi saranno probabilmente connessi all'avvio dal Environment implementazione (ma in ogni caso è facile per voi per afferrare quello e l'accesso nel codice launcher - l'toString() di teh Environment elencherà i profili attivi credo) . I profili attivi (e altri ancora) sono disponibili anche nell'endpoint/env se si aggiunge l'attuatore.

5

servizio/env attuatore mostra proprietà, ma non visualizza quale valore della proprietà è attiva. Molto spesso si consiglia di ignorare le proprietà applicative con

  • proprietà applicative specifiche del profilo
  • argomenti della riga di comando
  • variabili d'ambiente OS

Così si avrà la stessa proprietà e valori diversi in diverse fonti.

Snippet stampe a soffietto attivi valori delle proprietà delle applicazioni all'avvio:

@Configuration 
public class PropertiesLogger { 
    private static final Logger log = LoggerFactory.getLogger(PropertiesLogger.class); 

    @Autowired 
    private AbstractEnvironment environment; 

    @PostConstruct 
    public void printProperties() { 

     log.info("**** APPLICATION PROPERTIES SOURCES ****"); 

     Set<String> properties = new TreeSet<>(); 
     for (PropertiesPropertySource p : findPropertiesPropertySources()) { 
      log.info(p.toString()); 
      properties.addAll(Arrays.asList(p.getPropertyNames())); 
     } 

     log.info("**** APPLICATION PROPERTIES VALUES ****"); 
     print(properties); 

    } 

    private List<PropertiesPropertySource> findPropertiesPropertySources() { 
     List<PropertiesPropertySource> propertiesPropertySources = new LinkedList<>(); 
     for (PropertySource<?> propertySource : environment.getPropertySources()) { 
      if (propertySource instanceof PropertiesPropertySource) { 
       propertiesPropertySources.add((PropertiesPropertySource) propertySource); 
      } 
     } 
     return propertiesPropertySources; 
    } 

    private void print(Set<String> properties) { 
     for (String propertyName : properties) { 
      log.info("{}={}", propertyName, environment.getProperty(propertyName)); 
     } 
    } 

} 
+0

Questo stampato nulla per me. – pacoverflow

+0

Niente? Vuoi dire che nemmeno "**** APPLICATION PROPERTIES SOURCES ****" è stampato su @PostConstruct? Innanzitutto, assicurati che l'oggetto PropertiesLogger sia stato creato completamente nella tua applicazione. Forse alcuni suggerimenti su @EnableAutoConfiguration possono aiutare. –

+1

Voglio dire che ha stampato "**** FONTI PROPRIETÀ DELL'APPLICAZIONE ****" seguito da nulla seguito da "**** VALORI PROPRIETÀ DELL'APPLICAZIONE ****" seguito da nulla. – pacoverflow

0

Nel caso in cui si desidera ottenere i profili attivi prima di inizializzare il fagioli/applicazione, l'unico modo che ho trovato sta registrando un banner personalizzato in SpringApplication/Costruttore.

0

Oltre alle altre risposte: registrazione delle proprietà attive sull'evento di aggiornamento del contesto.

Java 8

package mypackage; 

import lombok.extern.slf4j.Slf4j; 
import org.springframework.context.event.ContextRefreshedEvent; 
import org.springframework.context.event.EventListener; 
import org.springframework.core.env.ConfigurableEnvironment; 
import org.springframework.core.env.MapPropertySource; 
import org.springframework.stereotype.Component; 

import java.util.ArrayList; 
import java.util.Collection; 
import java.util.List; 

@Slf4j 
@Component 
public class AppContextEventListener { 

    @EventListener 
    public void handleContextRefreshed(ContextRefreshedEvent event) { 
     printActiveProperties((ConfigurableEnvironment) event.getApplicationContext().getEnvironment()); 
    } 

    private void printActiveProperties(ConfigurableEnvironment env) { 

     System.out.println("************************* ACTIVE APP PROPERTIES ******************************"); 

     List<MapPropertySource> propertySources = new ArrayList<>(); 

     env.getPropertySources().forEach(it -> { 
      if (it instanceof MapPropertySource && it.getName().contains("applicationConfig")) { 
       propertySources.add((MapPropertySource) it); 
      } 
     }); 

     propertySources.stream() 
       .map(propertySource -> propertySource.getSource().keySet()) 
       .flatMap(Collection::stream) 
       .distinct() 
       .sorted() 
       .forEach(key -> { 
        try { 
         System.out.println(key + "=" + env.getProperty(key)); 
        } catch (Exception e) { 
         log.warn("{} -> {}", key, e.getMessage()); 
        } 
       }); 
     System.out.println("******************************************************************************"); 
    } 
} 

Kotlin

package mypackage 

import mu.KLogging 
import org.springframework.context.event.ContextRefreshedEvent 
import org.springframework.context.event.EventListener 
import org.springframework.core.env.ConfigurableEnvironment 
import org.springframework.core.env.MapPropertySource 
import org.springframework.stereotype.Component 

@Component 
class AppContextEventListener { 

    companion object : KLogging() 

    @EventListener 
    fun handleContextRefreshed(event: ContextRefreshedEvent) { 
     printActiveProperties(event.applicationContext.environment as ConfigurableEnvironment) 
    } 

    fun printActiveProperties(env: ConfigurableEnvironment) { 
     println("************************* ACTIVE APP PROPERTIES ******************************") 
     env.propertySources 
       .filter { it is MapPropertySource } 
       .map { it as MapPropertySource } 
       .filter { it.name.contains("applicationConfig") } 
       .map { it -> it.source.keys } 
       .flatMap { it } 
       .distinctBy { it } 
       .sortedBy { it } 
       .forEach { it -> 
        try { 
         println("$it=${env.getProperty(it)}") 
        } catch (e: Exception) { 
         logger.warn("$it -> ${e.message}") 
        } 
       } 
     println("******************************************************************************") 
    } 
} 

uscita come:.

************************* ACTIVE APP PROPERTIES ****************************** 
server.port=3000 
spring.application.name=my-app 
... 
2017-12-29 13:13:32.843 WARN 36252 --- [   main] m.AppContextEventListener  : spring.boot.admin.client.service-url -> Could not resolve placeholder 'management.address' in value "http://${management.address}:${server.port}" 
... 
spring.datasource.password= 
spring.datasource.url=jdbc:postgresql://localhost/my_db?currentSchema=public 
spring.datasource.username=db_user 
... 
****************************************************************************** 
Problemi correlati