2013-07-01 11 views
11

Sto utilizzando Spring 3.2 in un'applicazione Web e mi piacerebbe avere un file .properties all'interno del classpath che contiene valori predefiniti. L'utente dovrebbe essere in grado di utilizzare JNDI per definire una posizione in cui è memorizzato un altro .properties che sostituisce i valori predefiniti.Facoltativo @PropertySource posizione

Quanto segue funziona fintanto che l'utente ha impostato configLocation come proprietà JNDI.

@Configuration 
@PropertySource({ "classpath:default.properties", "file:${java:comp/env/configLocation}/override.properties" }) 
public class AppConfig 
{ 
} 

Tuttavia, le sostituzioni esterne devono essere facoltative e, quindi, deve essere la proprietà JNDI.

Attualmente ottengo un'eccezione (java.io.FileNotFoundException: comp\env\configLocation\app.properties (The system cannot find the path specified) quando la proprietà JNDI manca.

Come posso definire opzionale .properties che vengono utilizzati solo quando la proprietà JNDI (configLocation) è impostato? Questo è anche possibile con @PropertySource o è c'è un'altra soluzione

risposta

3

Provate il seguente Creare un ApplicationContextInitializer

in un contesto Web:?. ApplicationContextInitializer<ConfigurableWebApplicationContext> e registrarlo nel web.xml via:

<context-param> 
    <param-name>contextInitializerClasses</param-name> 
    <param-value>...ContextInitializer</param-value> 
</context-param> 

In ContextInitializer è possibile aggiungere i file delle proprietà tramite classpath e file system (tuttavia non è stato provato JNDI).

public void initialize(ConfigurableWebApplicationContext applicationContext) { 
    String activeProfileName = null; 
    String location = null; 

    try { 
     ConfigurableEnvironment environment = applicationContext.getEnvironment(); 
     String appconfigDir = environment.getProperty(APPCONFIG); 
     if (appconfigDir == null) { 
     logger.error("missing property: " + APPCONFIG); 
     appconfigDir = "/tmp"; 
     } 
     String[] activeProfiles = environment.getActiveProfiles(); 

     for (int i = 0; i < activeProfiles.length; i++) { 
     activeProfileName = activeProfiles[i]; 
     MutablePropertySources propertySources = environment.getPropertySources(); 
     location = "file://" + appconfigDir + activeProfileName + ".properties"; 
     addPropertySource(applicationContext, activeProfileName, 
       location, propertySources); 
     location = "classpath:/" + activeProfileName + ".properties"; 
     addPropertySource(applicationContext, activeProfileName, 
          location, propertySources); 
     } 
     logger.debug("environment: '{}'", environment.getProperty("env")); 

    } catch (IOException e) { 
     logger.info("could not find properties file for active Spring profile '{}' (tried '{}')", activeProfileName, location); 
     e.printStackTrace(); 
    } 
    } 

    private void addPropertySource(ConfigurableWebApplicationContext applicationContext, String activeProfileName, 
           String location, MutablePropertySources propertySources) throws IOException { 
    Resource resource = applicationContext.getResource(location); 
    if (resource.exists()) { 
     ResourcePropertySource propertySource = new ResourcePropertySource(location); 
     propertySources.addLast(propertySource); 
    } else { 
     logger.info("could not find properties file for active Spring profile '{}' (tried '{}')", activeProfileName, location); 
    } 
    } 

Il codice di cui sopra tenta di trovare un file di proprietà per ogni profilo attivo (vedi: How to set active spring 3.1 environment profile via a properites file and not via an env variable or system property)

+0

Grazie. L'ho anche risolto usando un 'ApplicationContextInitializer'. Sembra che sia l'unico modo fattibile per farlo. –

33

partire dalla primavera 4, problema SPR-8371 è stato risolto. Di conseguenza, l'annotazione @PropertySource ha un nuovo attributo chiamato ignoreResourceNotFound che è stato aggiunto esattamente per questo scopo. Inoltre, v'è anche la nuova @PropertySources annotazione che permette implementazioni come:

@PropertySources({ 
    @PropertySource("classpath:default.properties"), 
    @PropertySource(value = "file:/path_to_file/optional_override.properties", ignoreResourceNotFound = true) 
}) 
+3

Nota come per JavaDoc '@ PropertySources', in Java 8, è possibile applicare direttamente più annotazioni' @ PropertySource' a una classe senza wrapper. –

+2

@ billc.cn Giusto. Ho scritto un [post di blog] (http://www.jayway.com/2014/02/16/spring-propertysource/) circa un anno fa su '@ PropertySource' in cui ho citato anche [le annotazioni ripetute di Java 8] (http://openjdk.java.net/jeps/120). – matsev

5

Se non sei ancora su Spring 4 (vedi la soluzione di matsev), ecco una soluzione più prolisso, ma grosso modo equivalente:

@Configuration 
@PropertySource("classpath:default.properties") 
public class AppConfig { 

    @Autowired 
    public void addOptionalProperties(StandardEnvironment environment) { 
     try { 
      String localPropertiesPath = environment.resolvePlaceholders("file:${java:comp/env/configLocation}/override.properties"); 
      ResourcePropertySource localPropertySource = new ResourcePropertySource(localPropertiesPath); 
      environment.getPropertySources().addLast(localPropertySource); 
     } catch (IOException ignored) {} 
    } 

} 
Problemi correlati