2009-06-25 21 views
19

Ho una classe di utilizzo statica che esegue alcune manipolazioni di stringhe su dati sensibili al bit. Prima di utilizzare questa classe ho bisogno di inizializzare determinate variabili statiche con valori, come nomi utente/password, che preferisco memorizzare in un file .properties.Carica le proprietà java all'interno del blocco di inizializzazione statico

Non ho molta familiarità con il modo in cui il caricamento del file .properties funziona in Java, in particolare al di fuori del contenitore * Spring DI *. Chiunque può darmi una mano/intuizione su come questo può essere fatto?

Grazie!

Aggiunta:.properties La posizione precisa del file è sconosciuta, ma sarà sul classpath. Sorta come classpath:/my/folder/name/myproperties.propeties

+0

Lei parla di primavera - si usa il framework nell'applicazione che incorpora questa classe di utilità statica? – teabot

+0

beh, è ​​un po 'strano. la classe verrà utilizzata all'interno di un'app che utilizza il contenitore a molla. la classe stessa però non verrà cablata usando spring, deve essere solo una classe di utilità statica che viene chiamata dai thread worker che sono cablati da Spring. Posso modificare i thread di lavoro, ma non posso modificare il cablaggio di quei thread (quindi non posso usare PropertyPlaceHolderConfigurer) ... hm, ha senso? :) – xelurg

risposta

24

Innanzitutto, ottenere uno InputStream da cui devono essere caricate le proprietà. Questo può venire da un certo numero di località, tra cui alcuni dei più probabili:

  • A FileInputStream, creata con un nome di file che è hard-coded o specificato tramite un system property. Il nome potrebbe essere relativo (per il lavoro corrente directory del processo Java) o assoluto.
  • Un file di risorse (un file sul classpath), ottenuto tramite una chiamata a getResourceAsStream su Class (relativo al file di classe) o ClassLoader (relativo alla radice del percorso di classe). Si noti che questi metodi restituiscono null se la risorsa è mancante, invece di generare un'eccezione.
  • A URL, che, come un nome file, potrebbe essere codificato o specificato tramite una proprietà di sistema.

quindi creare un nuovo Properties oggetto, e passare il InputStream al metodo load(). Assicurati di chiudere lo stream, indipendentemente da eventuali eccezioni.

In un inizializzatore di classe, devono essere gestite eccezioni controllate come IOException. È possibile generare un'eccezione non controllata, che impedirà l'inizializzazione della classe. Questo, a sua volta, di solito impedisce alla tua applicazione di funzionare affatto. In molte applicazioni, potrebbe essere preferibile utilizzare invece le proprietà predefinite o eseguire il fallback su un'altra fonte di configurazione, ad esempio richiedendo un utilizzo in un contesto interattivo.

Complessivamente, potrebbe essere simile a questo:

private static final String NAME = "my.properties"; 

private static final Properties config; 

static { 
    Properties fallback = new Properties(); 
    fallback.put("key", "default"); 
    config = new Properties(fallback); 

    URL res = MyClass.getResource(NAME); 
    if (res == null) throw new UncheckedIOException(new FileNotFoundException(NAME)); 
    URI uri; 
    try { uri = res.toURI(); } 
    catch (URISyntaxException ex) { throw new IllegalArgumentException(ex); } 

    try (InputStream is = Files.newInputStream(Paths.get(uri))) { config.load(is); } 
    catch (IOException ex) { throw new UncheckedIOException("Failed to load resource", ex); } 
} 
6
  1. Partenza java.util.Properties.

  2. È possibile utilizzare un inizializzatore statico. Quindi, sulla parte superiore della classe che si può fare:


static { 
    Properties props = new Properties(); 
    InputStream steam = ...; // open the file 
    props.load(stream); 

    // process properties content 
    String username = props.getProperty("username"); 
    } 
+0

Scusa, suppongo che stavi già formattando il codice mentre lo stavo facendo. –

+2

Potrebbe essere necessario gestire alcune eccezioni, poiché non penso che le eccezioni possano essere generate da un blocco statico. – Peter

+1

Le runtimeException possono essere generate da un blocco statico. Dovrai gestire le eccezioni controllate per le operazioni sui file. – akf

3

utilizzare:

CurrentClassName.class.getResourceAsStream 
new FileInputStream(File) 

per ottenere il flusso di input a seconda se la classe è dentro o fuori del classpath. Quindi utilizzare

Properties.load 

per caricare le proprietà.

2

E 'stato un po', ma se non ricordo male si solo fare qualcosa di simile:

Properties prop = new Properties(); 
prop.load(new FileInputStream(filename)); 

//For each property you need. 
blah = prop.getProperty(propertyname); 
1

Bene con proprietà statiche avrebbe senso per inizializzare loro come un Singleton, che verrà caricata una volta in una classe . Ecco un esempio:

class Example 
{ 
    public final static String PROPSFILE = "test.properties"; 

    private static Properties props; 

    protected static Properties getProperties() 
    { 
     if(props == null) 
     { 
      props = new Properties(); 
      props.load(new FileInputStream(new File(PROPSFILE)); 
     } 
     return props; 
    } 

    public static User getUser() 
    { 
     String username = getProperties().getProperty("username"); 
     return new User(username); 
    } 
} 

Se si utilizzano percorsi relativi, è necessario assicurarsi che il percorso di classe sia impostato correttamente.

+3

Quello non è un Singleton. È semplicemente una variabile statica e un metodo. La domanda non richiedeva l'accesso pubblico alle proprietà, ma l'inizializzazione dei membri statici da un file delle proprietà. – Robin

+0

Beh, personalmente non sono un fan dell'inizializzazione statica perché ha causato qualche problema in un progetto su cui stavo lavorando. Consiglierei di usare almeno metodi di produzione statici, dove mai possibile (ho aggiornato l'esempio per quello). Ma vero, non era in realtà la domanda. – Daff

0

Sono d'accordo con @Daff, forse meglio utilizzare classe Singleton ... questo quello che ho sul mio progetto per il requisito simile, forse può essere utile :

clienti della classe possono utilizzare in questo modo:

ConfigsLoader configsLoader = ConfigsLoader.getInstance("etc/configs.xml"); 

System.out.format("source dir %s %n", configsLoader.getSourceDir()); 

e poi la classe:

public class ConfigsLoader {

private String sourceDir; 
private String destination; 
private String activeMqUrl; 

private static Logger log = Logger.getLogger(ConfigsLoader.class.getName()); 

private static ConfigsLoader instance = null; 

private ConfigsLoader(String configFileName) { 
    log.info("loading configs"); 
    Properties configs = new Properties(); 
    try { 
     configs.loadFromXML(new FileInputStream(configFileName)); 

     sourceDir = configs.getProperty("source.dir"); 
     destination = configs.getProperty("destination"); 
     activeMqUrl = configs.getProperty("activemqconnectionurl"); 
     configs.setProperty("lastLoaded", new SimpleDateFormat("yyyy-M-d HH:mm").format(new Date())); 
     configs.storeToXML(new FileOutputStream(configFileName), "saving last modified dates"); 

    } catch (InvalidPropertiesFormatException e) { 
     log.log(Level.SEVERE,"Error occured loading the properties file" ,e); 
    } catch (FileNotFoundException e) { 
     log.log(Level.SEVERE,"Error occured loading the properties file" ,e); 
    } catch (IOException e) { 
     log.log(Level.SEVERE,"Error occured loading the properties file" ,e); 
    } 
} 

public static ConfigsLoader getInstance(String configFileName) { 
    if(instance ==null) { 
     instance = new ConfigsLoader(configFileName); 
    } 

    return instance; 
} 

public String getSourceDir() { 
    return sourceDir; 
} 

public void setSourceDir(String sourceDir) { 
    this.sourceDir = sourceDir; 
} 

public String getDestination() { 
    return destination; 
} 

public void setDestination(String destination) { 
    this.destination = destination; 
} 

public String getActiveMqUrl() { 
    return activeMqUrl; 
} 

public void setActiveMqUrl(String activeMqUrl) { 
    this.activeMqUrl = activeMqUrl; 
} 

}

0

ho fatto finalmente usando getResourceAsStream fuction() associato alla classe in cui viene scritto il blocco di codice statico.

//associate Property and ImputStream imports 
public class A { 
    static Properties p; 
    static { 
     p = new Properties(); 
     try { 
      InputStream in = A.class.getResourceAsStream("filename.properties"); 
      p.load(in); 
     } catch (FileNotFoundException e) { 
     System.out.println("FileNotFoundException"); 
     e.printStackTrace(); 
     } catch (IOException e) { 
     System.out.println("IOException"); 
     e.printStackTrace(); 
     } 
    } 
    . 
    . 
    . 
} 
0

per me MyClass.class.getClassLoader().getResourceAsStream(..) ha fatto il trucco:

private static final Properties properties; 

static { 
    Properties fallback = new Properties(); 
    fallback.put(PROP_KEY, FALLBACK_VALUE); 

    properties = new Properties(fallback); 

    try { 
     try (InputStream stream = MyClass.class.getClassLoader().getResourceAsStream("myProperties.properties")) { 
      properties.load(stream); 
     } 
    } catch (IOException ex) { 
     // handle error 
    } 
} 
Problemi correlati