Qual è il modo migliore per leggere i parametri di configurazione dal file di configurazione in Java?


Assumiamo fino a runtime non sappiamo quali sono i dettagli della configurazione(potrebbe essere necessario configurare questi parametri nel file config prima di eseguire l'applicazione.

Voglio leggere quei dettagli di configurazione e ho bisogno di riutilizzarli ovunque ne abbia bisogno nella mia applicazione. Per questo voglio renderli come costanti globali (public static final).

Quindi, il mio dubbio è, ci sono implicazioni sulle prestazioni se leggo dal file config direttamente dalla classe richiesta? dal momento che, runtime valori che non posso inserire direttamente in Interface separati.

Penso che avrà un impatto sulle prestazioni.Per favore suggeriscimi un modo migliore per farlo.

AGGIORNAMENTO: Posso usare una classe finale separata per i dettagli della configurazione? mettere tutti i dettagli di configurazione come costanti in un public final class {[16 separato]} (Per leggere tutti i dettagli di configurazione contemporaneamente dal file di configurazione e memorizzarli come costanti globali per un uso successivo nell'applicazione)

Author: Sagar Pudi, 2014-11-13

10 answers

Penso che avrà un impatto sulle prestazioni.

Dubito che questo sarà vero.

Supponendo che l'applicazione legga il file di configurazione solo una volta all'avvio, il tempo impiegato per leggere il file è probabilmente irrilevante per le prestazioni complessive dell'applicazione. Infatti, più a lungo l'applicazione viene eseguita, il tempo di avvio meno importante sarà.

Il consiglio standard consiste nell'ottimizzare le prestazioni dell'applicazione solo quando si hanno prove concrete (cioè misurazioni) per dire che le prestazioni sono un problema significativo. Quindi, ottimizza solo quelle parti del tuo codice che la profilazione ti dice che sei davvero un collo di bottiglia delle prestazioni.


Posso usare una classe finale separata per i dettagli di configurazione

Sì, è possibile farlo. Nessuno ti fermerà1. Tuttavia, è una cattiva idea. Tutto ciò che significa che è necessario ricompilare il codice per modificare la configurazione parametri è una cattiva idea. IMO.


Per leggere tutti i dettagli di configurazione contemporaneamente dal file di configurazione e memorizzarli come costanti globali per un uso successivo nell'applicazione.

Ah ... quindi vuoi leggere i valori delle "costanti"invece di cablarle.

Sì, è possibile. E ha più senso di parametri di configurazione hard-cablaggio nel codice. Ma non è ancora una buona idea (IMO).

Perché? Bene lascia guardare come deve essere il codice:

public final class Config { 
    public static final int CONST_1;
    public static final String CONST_2;

    static {
        int c1;
        String c2;
        try (Scanner s = new Scanner(new File("config.txt"))) {
            c1 = s.nextInt();
            c2 = s.next();
        } catch (IOException ex) {
            throw RuntimeException("Cannot load config properties", ex);
        }
        CONST_1 = c1;
        CONST_2 = c2; 
    }
}

La prima osservazione è che non fa differenza che la classe sia final. Sta dichiarando i campi come final che li rende costanti. (Dichiarare la classe come final impedisce la sottoclasse, ma ciò non ha alcun impatto sui campi static. I campi statici non sono influenzati dall'ereditarietà.)

La prossima osservazione è che questo codice è fragile sotto diversi aspetti:

  • Se qualcosa va storto nella statica blocco inizializzatore. l'eccezione non selezionata generata dal blocco verrà avvolta come ExceptionInInitializerError (sì ... è un Error!!), e la classe Config sarà contrassegnata come errata.

  • Se ciò accade, non c'è alcuna speranza realistica di recuperare, ed è forse anche una cattiva idea cercare di diagnosticare il Error.

  • Il codice sopra viene eseguito quando la classe Config viene inizializzata, ma determinare quando ciò accade può essere complicato.

  • Se il il nome del file di configurazione è un parametro, quindi hai il problema di ottenere il valore del parametro ... prima che venga attivata l'inizializzazione statica.

Successivamente, il codice è piuttosto disordinato rispetto al caricamento dello stato in variabili di istanza. E quella confusione è in gran parte il risultato di dover lavorare all'interno dei vincoli degli inizializzatori statici. Ecco come appare il codice se si utilizzano invece le variabili di istanza final.

public final class Config { 
    public final int CONST_1;
    public final String CONST_2;

    public Config(File file) throws IOException {
        try (Scanner s = new Scanner(file)) {
            CONST_1 = s.nextInt();
            CONST_2 = s.next();
        } 
    }
}

Infine, la performance i vantaggi dei campi static final rispetto ai campi final sono minuscoli:

  • Probabilmente una o due istruzioni della macchina ogni volta che si accede a una delle costanti,

  • Forse nulla se il compilatore JIT è intelligente e gestisci il riferimento singleton Config in modo appropriato.

In entrambi i casi, nella stragrande maggioranza dei casi i benefici saranno insignificanti.


1 - OK ... se il tuo codice è rivisto dal codice, allora qualcuno lo farà probabilmente ti fermera'.

 18
Author: Stephen C, 2017-07-25 09:27:29

Avete mai sentito parlare di apache commons configuration http://commons.apache.org/proper/commons-configuration / ? È il miglior lettore di configurazione che abbia mai trovato e lo sto usando nella mia applicazione che è in esecuzione in produzione da 1 anno. Mai trovato problemi, molto facile da capire e da usare, grandi prestazioni. So che è un po ' di dipendenza dalla tua applicazione, ma fidati di me ti piacerà.

Tutto quello che devi fare è

Configuration config = new ConfigSelector().getPropertiesConfiguration(configFilePath);
String value = config.getString("key");
int value1 = config.getInt("key1");
String[] value2 = config.getStringArray("key2");
List<Object> value3 = config.getList("key3");

E questo è tutto. Vostro config object manterrà tutti i valori di configurazione e puoi semplicemente passare quell'oggetto a tutte le classi che vuoi. Con così tanti metodi utili disponibili puoi estrarre qualsiasi tipo di chiave tu voglia.

 19
Author: Sri777, 2014-11-24 11:56:08

Sarà solo un costo di tempo se li stai mettendo in un file di proprietà e leggendo il file all'inizio della tua applicazione e inizializzi tutti i parametri come parametri di sistema( Sistema.setProperty ) e quindi definire costanti nel codice come

public static final String MY_CONST = System.getProperty("my.const");

Ma assicurati l'inizializzazione all'inizio dell'applicazione prima che venga caricata qualsiasi altra classe.

 5
Author: Sanjeev Kumar, 2014-11-13 12:31:49

Esistono diversi tipi di configurazione.

Di solito è necessaria una sorta di configurazione di bootstrap, ad esempio per connettersi a un database o un servizio, per poter avviare l'applicazione. Il modo J2EE per specificare i parametri di connessione al database è tramite un 'datasource' specificato nel registro JNDI del contenitore (Glassfish, JBoss, Websphere,...). Questa origine dati viene quindi cercata per nome nella persistenza.XML. Nelle applicazioni non J2EE è più comune specificarle in un Contesto primaverile o anche un .file delle proprietà. In ogni caso, di solito hai bisogno di qualcosa per connettere la tua applicazione a una sorta di archivio dati.

Dopo il bootstrap in un archivio dati un'opzione è quella di gestire i valori di configurazione all'interno di questo datastore. Ad esempio, se si dispone di un database, è possibile utilizzare una tabella separata (rappresentata ad esempio da un'entità JPA nell'applicazione) per i valori di configurazione. Se non vuoi/hai bisogno di questa flessibilità puoi usare simple .file di proprietà per questo invece. C'è buona supporto per .file di proprietà in Java (ResourceBundle ) e in framework come Spring . Il vanilla ResourceBundle carica solo le proprietà una volta, l'helper Spring offre il caching e il ricaricamento configurabili (questo aiuta con l'aspetto delle prestazioni che hai menzionato). Nota: è inoltre possibile utilizzare le Proprietà supportate da un archivio dati anziché da un file.

Spesso entrambi gli approcci coesistono in un'applicazione. Valori che non cambiano mai all'interno di un'applicazione distribuita (come nome dell'applicazione) può essere letto da un file di proprietà. I valori che potrebbero dover essere modificati da un manutentore dell'applicazione in fase di runtime senza ridistribuzione (ad es.file di proprietà o in un database. I valori che possono essere modificati dagli utenti dell'applicazione devono essere conservati nell'archivio dati dell'applicazione e di solito hanno una schermata in-application per modificarli.

Quindi il mio consiglio è di separare le impostazioni di configurazione in bootstrap, distribuzione, runtime e applicazione) e selezionare un meccanismo appropriato per gestirli. Ciò dipende anche dall'ambito della tua applicazione, ovvero è un'app Web J2EE, un'app desktop, un'utilità da riga di comando, un processo batch?

 4
Author: Adriaan Koster, 2014-11-26 09:17:00

Che tipo di file di configurazione hai in mente? Se si tratta di un file di proprietà, questo potrebbe essere adatto a te:

public class Configuration {

    // the configuration file is stored in the root of the class path as a .properties file
    private static final String CONFIGURATION_FILE = "/configuration.properties";

    private static final Properties properties;

    // use static initializer to read the configuration file when the class is loaded
    static {
        properties = new Properties();
        try (InputStream inputStream = Configuration.class.getResourceAsStream(CONFIGURATION_FILE)) {
            properties.load(inputStream);
        } catch (IOException e) {
            throw new RuntimeException("Failed to read file " + CONFIGURATION_FILE, e);
        }
    }

    public static Map<String, String> getConfiguration() {
        // ugly workaround to get String as generics
        Map temp = properties;
        Map<String, String> map = new HashMap<String, String>(temp);
        // prevent the returned configuration from being modified 
        return Collections.unmodifiableMap(map);
    }


    public static String getConfigurationValue(String key) {
        return properties.getProperty(key);
    }

    // private constructor to prevent initialization
    private Configuration() {
    }

}

È anche possibile restituire l'oggetto Properties immediatamente dal metodo getConfiguration(), ma potrebbe potenzialmente essere modificato dal codice che vi accede. Collections.unmodifiableMap() non rende la configurazione costante (poiché l'istanza Properties ottiene i suoi valori con il metodo load() dopo che è stata creata), tuttavia poiché è racchiusa in una mappa non modificabile, la configurazione non può essere modificato da altre classi.

 3
Author: matsev, 2014-11-23 21:38:10

Bene, questo è un grande problema che viene affrontato nella vita di ognuno una volta in un testamento. Ora venendo al problema, questo può essere risolto creando una classe singleton che ha variabili di istanza uguali a quelle del file di configurazione con valori predefiniti. In secondo luogo questa classe dovrebbe avere un metodo come getInstance() che legge le proprietà una volta e ogni volta restituisce lo stesso oggetto se esiste. Per la lettura del file possiamo usare la variabile ambientale per ottenere path o qualcosa come System.getenv("Config_path");. Lettura del proprietà (readProperties() metodo) dovrebbe leggere ogni elemento dal file di configurazione e impostare il valore per le variabili di istanza di oggetto singleton. Quindi ora un singolo oggetto contiene tutto il valore del parametro di configurazione e anche se il parametro è vuoto rispetto al valore predefinito.

 3
Author: Bhargav Modi, 2014-11-26 13:31:06

Un altro modo è definire una classe e leggere il file delle proprietà in quella classe. Questa classe deve essere a livello di applicazione e può essere contrassegnata come Singleton. Contrassegnare la classe come Singleton eviterà la creazione di più istanze.

 2
Author: Yusuf Kapasi, 2014-11-19 07:05:11

Mettere le chiavi di configurazione direttamente alle classi è sbagliato: le chiavi di configurazione saranno sparse sul codice. La migliore pratica è la separazione del codice dell'applicazione e del codice di configurazione. Di solito viene utilizzato il framework di iniezione delle dipendenze come spring. Carica un file di configurazione e costruisce gli oggetti utilizzando i valori di configurazione. Se hai bisogno di un valore di configurazione nella tua classe, dovresti creare un setter per questo valore. Spring imposterà questo valore durante l'inizializzazione del contesto.

 0
Author: Denis Borovikov, 2014-11-13 12:44:48

Raccomando di usare JAXB o un framework di associazione simile che funziona con file basati su testo. Poiché un'implementazione JAXB fa parte del JRE, è abbastanza facile da usare. Come Denis sconsiglio le chiavi di configurazione.

Ecco un semplice esempio per un modo facile da usare e ancora abbastanza potente per configurare l'applicazione con XML e JAXB. Quando si utilizza un framework DI, è sufficiente aggiungere un oggetto di configurazione simile al contesto DI.

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class ApplicationConfig {

    private static final JAXBContext CONTEXT;
    public static final ApplicationConfig INSTANCE;

    // configuration properties with defaults
    private int number = 0;
    private String text = "default";
    @XmlElementWrapper
    @XmlElement(name = "text")
    private List<String> texts = new ArrayList<>(Arrays.asList("default1", "default2"));

    ApplicationConfig() {
    }

    static {
        try {
            CONTEXT = JAXBContext.newInstance(ApplicationConfig.class);
        } catch (JAXBException ex) {
            throw new IllegalStateException("JAXB context for " + ApplicationConfig.class + " unavailable.", ex);
        }
        File applicationConfigFile = new File(System.getProperty("config", new File(System.getProperty("user.dir"), "config.xml").toString()));
        if (applicationConfigFile.exists()) {
            INSTANCE = loadConfig(applicationConfigFile);
        } else {
            INSTANCE = new ApplicationConfig();
        }
    }

    public int getNumber() {
        return number;
    }

    public String getText() {
        return text;
    }

    public List<String> getTexts() {
        return Collections.unmodifiableList(texts);
    }

    public static ApplicationConfig loadConfig(File file) {
        try {
            return (ApplicationConfig) CONTEXT.createUnmarshaller().unmarshal(file);
        } catch (JAXBException ex) {
            throw new IllegalArgumentException("Could not load configuration from " + file + ".", ex);
        }
    }

    // usage
    public static void main(String[] args) {
        System.out.println(ApplicationConfig.INSTANCE.getNumber());
        System.out.println(ApplicationConfig.INSTANCE.getText());
        System.out.println(ApplicationConfig.INSTANCE.getTexts());
    }
}

Il file di configurazione è simile a questo:

<?xml version="1.0" encoding="UTF-8"?>
<applicationConfig>
    <number>12</number>
    <text>Test</text>
    <texts>
        <text>Test 1</text>
        <text>Test 2</text>
    </texts>
</applicationConfig>
 0
Author: chromanoid, 2017-05-23 12:32:17
  protected java.util.Properties loadParams() throws IOException {
  // Loads a ResourceBundle and creates Properties from it
  Properties prop = new Properties();
  URL propertiesFileURL = this.getClass().getResource("/conf/config.properties");
  prop.load(new FileInputStream(new File(propertiesFileURL.getPath())));
  return prop;
  }


Properties prop = loadParams();
String prop1=(String) prop.get("x.y.z");
 0
Author: Sebri Zouhaier, 2014-11-24 13:38:13