2014-09-15 11 views
49

ho più file di proprietà che voglio caricare da classpath. C'è un valore predefinito sotto /src/main/resources che fa parte di myapp.jar. Il mio springcontext si aspetta che i file si trovino sul classpath. cioèfile di configurazione esterna primavera di avvio e molteplici

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

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

ho bisogno anche la possibilità di ignorare queste proprietà con un set esterno. Ho una cartella di configurazione esterna in cwd. Come per la primavera, la cartella di configurazione del documento di avvio dovrebbe trovarsi su classpath. Ma non è chiaro da doc se solo sostituirà lo applicaiton.properties da lì o tutte le proprietà in config.

Al momento del test, viene prelevato solo il numero application.properties e il resto delle proprietà viene prelevato da /src/main/resources. Ho provato a fornirli come elenco separato da virgole a spring.config.location ma il set predefinito non è ancora stato sostituito.

Come faccio mulitiple file di configurazione esterni sovrascrivono quelli di default?

Come soluzione che attualmente utilizzati app.config.location (app proprietà specifica) che fornisco attraverso la linea di comando. cioè

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

e ho cambiato il mio applicationcontext a

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

Ed è così che faccio separazione tra file e il percorso di classe durante il caricamento delle applicazioni.
Modifiche:

//psuedo code 

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

Mi piacerebbe davvero di non utilizzare la soluzione precedente e hanno primavera override di tutti i file di configurazione esterni nel classpath come avviene per il file application.properties.

+2

Il 'application.properties' sarà sempre caricato, con' spring.config.location' è possibile aggiungere ulteriori posizioni di configurazione che vengono controllati per i file (cioè quando termina con un '/'), tuttavia se si inserisce una lista separata da virgola in quella che punta ai file che verranno caricati. Questo è anche spiegato nella Guida di riferimento del boot di primavera [qui] (http://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html#boot-features- external-config-application-property-files) –

risposta

68

Usando Spring avvio le proprietà vengono caricati nel seguente ordine (vedi Externalized Configuration nella guida di riferimento di avvio Spring).

  1. Argomenti della riga di comando.
  2. Proprietà del sistema Java (System.getProperties()).
  3. Variabili di ambiente del sistema operativo.
  4. Attributi JNDI da java: comp/env
  5. A RandomValuePropertySource che ha solo proprietà in ordine casuale. *.
  6. Proprietà dell'applicazione al di fuori del vaso confezionato (proprietà applicative incluso YAML e varianti del profilo).
  7. Proprietà dell'applicazione impacchettate all'interno del vaso (proprietà dell'applicazione, comprese varianti YAML e profilo).
  8. annotazioni @PropertySource sulle classi @Configuration.
  9. Proprietà predefinite (specificate utilizzando SpringApplication.setDefaultProperties).

Quando risoluzione delle proprietà (cioè @Value("${myprop}") risolutivo è fatto in ordine inverso (così iniziano 9).

Per aggiungere file diversi è possibile utilizzare le proprietà spring.config.location che accettano un elenco separato da virgole di file di proprietà o percorso file (directory).

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

quello di cui sopra aggiungerà una directory che verrà consultato per application.properties file.

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

Questo aggiungerà il file delle 2 proprietà ai file che vengono caricati.

I file di configurazione di default e le posizioni vengono caricati prima della Additonally specificato spring.config.location quelli che significa che queste ultime saranno sempre ignorare le proprietà impostate in quelli precedenti. (Vedi anche this section della Guida di riferimento del boot di primavera).

Se spring.config.location contiene le directory (al contrario di file) che dovrebbe finire in/(e sarà aggiunto con i nomi generati dal spring.config.name prima di essere caricati). Il percorso di ricerca predefinito classpath:,classpath:/config,file:,file:config/ viene sempre utilizzato, indipendentemente dal valore di spring.config.location. In questo modo è possibile impostare i valori predefiniti per l'applicazione in application.properties (o qualsiasi altro nome di base che si sceglie con spring.config.name) e sovrascriverlo in fase di runtime con un file diverso, mantenendo i valori predefiniti.

+1

Grazie, ma ho già letto questo documento ref e in seguito mi confonde "-Dspring.config.location = il tuo/config/dir/ Quello sopra aggiungerà una directory che essere consultato per i file application.properties. " Che cosa significa i file application.properties. Questo è solo un file. In ogni caso, se è in grado di raccogliere l'intera directory con "/" alla fine, non è necessario specificare ciascuna come lista separata da virgole. Penso di aver provato entrambi gli approcci come ho detto nel mio post, ma gli darò un altro tentativo – nir

+0

Come indicato nel documento, verrà scelto come le altre posizioni predefinite per 'application.properties' e' application- [ env] .properties'. Non tiene conto di altri file di proprietà. Questo è anche indicato nella guida di riferimento (nella sezione il link porta a e la citazione dalla guida di riferimento). –

+0

Sì, ma questo è ciò che non ha senso per me .. perché prendere in considerazione solo un tipo di file da una directory su classpath invece di un'intera directory. Ti costringe a usare solo un file di proprietà che non è buono. Come in tomcat posso configurare il comune.loader per mettere directory particolare (e tutto ciò che lo ha isolato) su classpath, perché il bootloader non può avviarlo. – nir

16

Dai un'occhiata a PropertyPlaceholderConfigurer, lo trovo più chiaro da usare rispetto all'annotazione.

ad es.

@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

Ho appena avuto un problema simile a questo e finalmente capito la causa: il file application.properties aveva gli attributi di proprietà e RWX sbagliate. Così, quando Tomcat avviato il file application.properties era nella posizione giusta, ma di proprietà di un altro utente:

$ chmod 766 application.properties 

$ chown tomcat application.properties 
4

Ho avuto lo stesso problema. Volevo avere la possibilità di sovrascrivere un file di configurazione interno all'avvio con un file esterno, simile al rilevamento di applicazione.properties Spring Boot. Nel mio caso si tratta di un file user.properties in cui sono archiviati gli utenti delle mie applicazioni.

mie esigenze:

caricare il file dai seguenti percorsi (in questo ordine)

  1. classpath
  2. A /config subdir della directory corrente.
  3. La directory corrente
  4. Da directory o un percorso di file dato da un parametro di riga di comando all'avvio

mi si avvicinò con la seguente soluzione:

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

} 

Ora l'applicazione utilizza il classpath risorsa, ma controlla anche una risorsa nelle altre posizioni specificate.L'ultima risorsa esistente verrà raccolta e utilizzata. Sono in grado di avviare la mia app con java -jar myapp.jar --properties.location =/directory/myproperties.properties per utilizzare una posizione delle proprietà che fa galleggiare la mia barca.

Un dettaglio importante qui: utilizzare una stringa vuota come valore predefinito per il parametro properties.location nell'annotazione @Value per evitare errori quando la proprietà non è impostata.

La convenzione per una proprietà.location è: Utilizzare una directory o un percorso per un file di proprietà come properties.location.

Se si desidera sovrascrivere solo proprietà specifiche, è possibile utilizzare PropertiesFactoryBean con setIgnoreResourceNotFound (true) con l'array di risorse impostato come posizioni.

Sono sicuro che questa soluzione può essere estesa per gestire più file ...

EDIT

Ecco la mia soluzione per più file :) Come prima, questo può essere combinato con un 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; 
    } 

} 
+0

buona soluzione. Come quei costrutti java8! comunque non posso usarlo perché ho bisogno di più bean Proprietà non solo uno. Se vedi i miei EDITS la mia soluzione alternativa è abbastanza simile e ordinata per il mio caso d'uso. – nir

+0

Ho postato una versione per più file, solo per completezza;) – mxsb

3

questo è un approccio semplice di avvio utilizzando primavera

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

le app.properties contesto, nella tua posizione selezionata

test.one = 1234 

l'applicazione di avvio primavera

@SpringBootApplication 

public class TestApplication { 

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

e il predefinito application.properties contesto

spring.profiles.active = one 

è possibile scrivere il maggior numero classe di configurazione come ti piace e attivare/disattivare loro solo impostando spring.profiles.active = il nome profilo/nomi {separati da virgole}

come si può vedere avvio primavera è grande ha solo bisogno di qualche tempo per acquisire familiarità con, vale la pena ricordare che si può utilizzare @Value sui vostri campi così

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

Con avvio di primavera, lo spring.config.location funziona, basta fornire file di proprietà separati da virgola.

vedere il codice qui sotto

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

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

si può mettere la versione di default di jdbc.properties all'interno dell'applicazione. Le versioni esterne possono essere impostate per questo.

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

basato sul valore di profilo impostato utilizzando la proprietà spring.profiles.active, il valore di jdbc.host saranno raccolti. Così, quando (su Windows)

set spring.profiles.active=dev 

jdbc.host avrà valore dal jdbc-dev.properties.

per

set spring.profiles.active=default 

jdbc.host avrà valore dal jdbc.properties.

3

avvio primavera ci permette di scrivere diversi profili di scrivere per diversi ambienti, ad esempio, possiamo avere file di proprietà separate per la produzione, QA e ambienti locali archiviano

application-local.properties con configurazioni secondo la mia macchina locale è

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 

Allo stesso modo, possiamo scrivere application-prod.properties e application-qa.properties il maggior numero di file di proprietà come vogliamo

quindi scrivere alcuni script per avviare il applicazione per diversi ambienti, ad es.

mvn spring-boot:run -Drun.profiles=local 
mvn spring-boot:run -Drun.profiles=qa 
mvn spring-boot:run -Drun.profiles=prod 
0

ho trovato questo per essere un modello utile da seguire:

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

Qui ridefiniamo l'uso di "application.yml" da usare "application-MyTest_LowerImportance.yml" e anche "applicazione -MyTest_MostImportant.yml"
(primavera sarà anche cercare i file .properties)

inclusi anche come un bonus extra sono il debug e trace impostazioni, su una riga separata in modo da poterli commentare, se richiesto;]

Il debug/trace è incredibilmente utile in quanto Spring scaricherà i nomi di tutti i file che carica e quelli che tenta di caricare.
Vedrete linee come questo nella console in fase di esecuzione:

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