Quelle est la meilleure façon de lire les paramètres de configuration à partir du fichier de configuration en Java?


Supposons jusqu'à l'exécution, nous ne savons pas quels sont les détails de configuration(mai besoin de l'utilisateur pour configurer ces paramètres dans config fichier avant d'exécuter l'application.

Je veux lire ces détails de configuration et je dois les réutiliser partout où j'en ai besoin dans mon application. Pour cela, je veux en faire des constantes globales (public static final).

Donc, Mon doute est, y a-t-il des implications de performance si je lis du fichier config directement à partir de la classe requise? depuis,la durée d'exécution valeurs que je ne peux pas mettre directement dans séparé Interface.

Je pense que cela aura un impact sur les performances.Veuillez me suggérer une meilleure façon de le faire.

MISE À JOUR: Puis-je utiliser une classe finale distincte pour les détails de configuration? mettre tous les détails de configuration en tant que constantes dans un public final class {[16 séparé]} (Pour lire tous les détails de configuration à la fois à partir du fichier de configuration et les stocker en tant que constantes globales pour une utilisation ultérieure dans l'application)

Author: Sagar Pudi, 2014-11-13

10 answers

Je pense que cela aura un impact sur la performance.

Je doute que cela soit vrai.

En supposant que l'application lit le fichier de configuration une seule fois au démarrage, le temps nécessaire à la lecture du fichier n'est probablement pas pertinent pour les performances globales de votre application. En effet, plus l'application s'exécute longtemps, moins le temps de démarrage sera important.

Le conseil standard consiste à optimiser les performances des applications uniquement lorsque vous disposez de preuves concrètes (c.-à-d. mesures) pour dire que la performance est un problème important. Ensuite, optimisez uniquement les parties de votre code que le profilage vous indique être vraiment un goulot d'étranglement des performances.


Puis-je utiliser une classe finale distincte pour les détails de configuration

Oui, il est possible de le faire. Personne ne va t'arrêter1. Cependant, c'est une mauvaise idée. Tout ce qui signifie que vous devez recompiler votre code pour modifier la configuration paramètres est une mauvaise idée. OMI.


Pour lire tous les détails de configuration à la fois à partir du fichier de configuration et les stocker en tant que constantes globales pour une utilisation ultérieure dans l'application.

Ah ... vous voulez donc lire les valeurs des" constantes " au lieu de les câbler en dur.

Oui, c'est possible. Et cela a plus de sens que les paramètres de configuration de câblage dur dans le code. Mais ce n'est toujours pas une bonne idée (OMI).

Pourquoi? Eh bien permet de regarder à quoi doit ressembler le code:

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

Première observation est que ne fait aucune différence que la classe est final. Il déclare les champs comme final ce qui les rend constants. (Déclarer la classe comme final empêche le sous-classement, mais cela n'a aucun impact sur les champs static. Les champs statiques ne sont pas affectés par l'héritage.)

L'observation suivante est que ce code est fragile à plusieurs égards:

  • Si quelque chose ne va pas dans le statique initialiseur de bloc. l'exception non cochée qui est levée par le bloc sera encapsulée en tant que ExceptionInInitializerError (oui ... c'est un Error!!), et la classe Config sera marquée comme erronée.

  • Si cela se produit, il n'est pas réaliste d'espoir de récupérer, et peut-être même une mauvaise idée d'essayer de diagnostiquer le Error.

  • Le code ci-dessus est exécuté lorsque la classe Config est initialisée, mais déterminer quand cela se produit peut être délicat.

  • Si le configuration filename est un paramètre, alors vous avez le problème de mettre la main sur la valeur du paramètre ... avant que l'initialisation statique ne soit déclenchée.

Ensuite, le code est assez désordonné par rapport au chargement de l'état dans une variable d'instance. Et ce désordre est en grande partie le résultat d'avoir à travailler dans les contraintes des initialiseurs statiques. Voici à quoi ressemble le code si vous utilisez des variables d'instance final à la place.

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

Enfin, la performance les avantages des champs static final sur les champs final sont minuscules:

  • Probablement une ou deux instructions machine chaque fois que vous accédez à l'une des constantes,

  • Peut-être rien du tout si le compilateur JIT est intelligent, et vous gérez la référence singleton Config de manière appropriée.

Dans les deux cas, dans la grande majorité des cas, les prestations seront insignifiants.


1 - OK ... si votre code est révisé, quelqu'un le fera probablement vous arrêter.

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

Avez - vous déjà entendu parler de la configuration apache commons http://commons.apache.org/proper/commons-configuration / ? C'est le meilleur lecteur de configuration que j'ai jamais trouvé et je l'utilise même dans mon application qui fonctionne en production depuis 1 an. Jamais trouvé de problèmes, très facile à comprendre et à utiliser, des performances exceptionnelles. Je sais que c'est un peu dépendant de votre application, mais croyez-moi, vous l'aimerez.

Tout ce que vous devez faire est

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");

Et c'est tout. Votre l'objet config contiendra toutes les valeurs de configuration et vous pouvez simplement passer cet objet à autant de classes que vous le souhaitez. Avec autant de méthodes utiles disponibles, vous pouvez extraire le type de clé que vous voulez.

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

Ce ne sera qu'un coût unique si vous les mettez dans un fichier de propriétés et lisez le fichier au début de votre application et initialisez tous les paramètres en tant que paramètres système( Système.setProperty ) puis définissez des constantes dans votre code comme

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

Mais assurez-vous de l'initialisation au début de votre application avant que toute autre classe ne soit chargée.

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

Il existe différents types de configuration.

Habituellement, une sorte de configuration d'amorçage, par exemple pour se connecter à une base de données ou à un service, est nécessaire pour pouvoir démarrer l'application. La façon J2EE de spécifier les paramètres de connexion à la base de données se fait via une' datasource ' spécifiée dans le registre JNDI de votre conteneur (Glassfish, JBoss, Websphere, ...). Cette source de données est ensuite recherchée par son nom dans votre persistance.XML. Dans les applications non-J2EE, il est plus courant de les spécifier dans un Contexte de printemps ou même un .fichier de propriétés. Dans tous les cas, vous avez généralement besoin de quelque chose pour connecter votre application à une sorte de magasin de données.

Après l'amorçage vers un magasin de données, une option consiste à gérer les valeurs de configuration dans ce magasin de données. Par exemple, si vous avez une base de données, vous pouvez utiliser une table séparée (représentée par une entité JPA dans votre application, par exemple) pour les valeurs de configuration. Si vous ne voulez pas/besoin de cette flexibilité vous pouvez utiliser simple .fichier de propriétés pour cela à la place. Il est bon soutien pour .fichiers de propriétés en Java (ResourceBundle ) et dans des frameworks comme Spring . Le ResourceBundle vanilla charge simplement les propriétés une fois, l'assistant Spring offre une mise en cache et un rechargement configurables (cela aide à l'aspect performance que vous avez mentionné). Remarque: vous pouvez également utiliser des propriétés sauvegardées par un magasin de données au lieu d'un fichier.

Souvent, les deux approches coexistent dans une application. Valeurs qui ne changent jamais dans une application déployée (comme nom de l'application) peut être lu à partir d'un fichier de propriétés. Les valeurs qui pourraient devoir être modifiées par un responsable d'application lors de l'exécution sans redéploiement (par exemple, l'intervalle de délai d'expiration de session) pourraient mieux être conservées dans un fichier rechargeable .fichier de propriétés ou dans une base de données. Des valeurs qui peuvent être modifiées par les utilisateurs de l'application doivent être conservées dans l'application de la banque de données et ont généralement une application de l'écran d'édition.

Donc mon conseil est de séparer vos paramètres de configuration en catégories (par exemple bootstrap, déploiement, exécution et application) et sélectionnez un mécanisme approprié pour les gérer. Cela dépend également de la portée de votre application, c'est-à-dire s'agit-il d'une application Web J2EE, d'une application de bureau, d'un utilitaire de ligne de commande, d'un processus par lots?

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

Quel type de fichier de configuration avez-vous en tête? S'il s'agit d'un fichier de propriétés, cela peut vous convenir:

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() {
    }

}

Vous pouvez également renvoyer l'objet Properties immédiatement à partir de la méthode getConfiguration(), mais il pourrait alors être modifié par le code qui y accède. Le {[3] } ne rend pas la configuration constante (puisque l'instance Properties obtient ses valeurs par la méthode load() après sa création), cependant, puisqu'elle est enveloppée dans une non modifiable map, la configuration ne peut pas être modifié par d'autres classes.

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

Eh Bien, ce est un grand problème auquel est confronté dans la vie de chacun une fois dans un testament. Maintenant, pour en venir au problème, cela peut être résolu en créant une classe singleton qui a des variables d'instance identiques à celles du fichier de configuration avec des valeurs par défaut. Deuxièmement, cette classe devrait avoir une méthode comme getInstance() qui lit les propriétés une fois et chaque fois renvoie le même objet s'il existe. Pour lire le fichier, nous pouvons utiliser une variable d'environnement pour obtenir path ou quelque chose comme System.getenv("Config_path");. La lecture de la les propriétés (méthodereadProperties()) doivent lire chaque élément du fichier de configuration et définir la valeur sur les variables d'instance de l'objet singleton. Donc maintenant, un seul objet contient toute la valeur du paramètre de configuration et aussi si le paramètre est vide que la valeur par défaut est considérée.

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

Une autre façon consiste à définir une classe et à lire le fichier de propriétés de cette classe. Cette classe doit être au niveau de l'application et peut être marquée comme Singleton. Marquer la classe comme Singleton évitera la création de plusieurs instances.

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

Mettre des clés de configuration directement dans les classes est mauvais: les clés de configuration seront dispersées sur le code. La meilleure pratique consiste à séparer le code d'application et le code de configuration. Habituellement, le framework d'injection de dépendance comme spring est utilisé. Il charge un fichier de configuration et construit les objets à l'aide de valeurs de configuration. Si vous avez besoin d'une valeur de configuration dans votre classe, vous devez créer un setter pour cette valeur. Spring définira cette valeur lors de l'initialisation du contexte.

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

Je recommande d'utiliser JAXB ou un framework de liaison similaire qui fonctionne avec des fichiers texte. Comme une implémentation JAXB fait partie du JRE, elle est assez facile à utiliser. CommeDenis je déconseille les clés de configuration.

Voici un exemple simple pour un moyen facile à utiliser et encore assez puissant pour configurer votre application avec XML et JAXB. Lorsque vous utilisez un framework DI, vous pouvez simplement ajouter un objet de configuration similaire au contexte 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());
    }
}

Le fichier de configuration ressemble à ceci:

<?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