Lecture des fichiers de configuration properties et XML en Java

Cinq méthodes pour lire les fichiers de configuration properties en Java

Contexte

Dans le développement d'un projet, il est souvent nécessaire de définir des variables personnalisées dans un fichier properties pour que le programme Java puisse les lire et les modifier dynamiquement. Cet article présente plusieurs méthodes pour lire les fichiers de configuration properties et XML dans un projet Spring+SpringMVC+Mybattis.

Environnement du projet

  • Spring 4.2.6.RELEASE
  • SpringMvc 4.2.6.RELEASE
  • Mybatis 3.2.8
  • Maven 3.3.9
  • Jdk 1.7
  • Idea 15.04

Cinq méthodes d'implémentation

Méthode 1: Utiliastion de context:property-placeholder pour charger les propriétés du fichier jdbc.properties

<context:property-placeholder location="classpath:jdbc.properties" ignore-unresolvable="true"/>

Cette configuration est équivalente à la suivante, mais plus concise:

<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
   <property name="ignoreUnresolvablePlaceholders" value="true"/>
   <property name="locations">
      <list>
         <value>classpath:jdbc.properties</value>
      </list>
    </property>
</bean>

Méthode 2: Injection via des annotations dans le code Java

<bean id="prop" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
   <property name="locations">
       <array>
          <value>classpath:jdbc.properties</value>
       </array>
   </property>
</bean>

Méthode 3: Exposition des propriétés avec l'étiquette util:properties

<util:properties id="propertiesReader" location="classpath:jdbc.properties"/>

Ajoutez la déclaration suivante dans le fichier spring-dao.xml:

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context-3.2.xsd
        http://www.springframework.org/schema/util
        http://www.springframework.org/schema/util/spring-util.xsd">

Méthode 4: Exposition des propriétés via PropertyPlaceholderConfigurer dans une sous-classe personnalisée

<bean id="propertyConfigurer" class="com.example.util.CustomPropertyConfigurer">
   <property name="ignoreUnresolvablePlaceholders" value="true"/>
   <property name="ignoreResourceNotFound" value="true"/>
   <property name="locations">
       <list>
          <value>classpath:jdbc.properties</value>
       </list>
   </property>
</bean>

Classe CustomPropertyConfigurer:

package com.example.util;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;

import java.util.Properties;

public class CustomPropertyConfigurer extends PropertyPlaceholderConfigurer {

    private Properties props;

    @Override
    protected void processProperties(ConfigurableListableBeanFactory beanFactoryToProcess, Properties props)
                            throws BeansException {
        super.processProperties(beanFactoryToProcess, props);
        this.props = props;
    }

    public String getProperty(String key) {
        return this.props.getProperty(key);
    }

    public String getProperty(String key, String defaultValue) {
        return this.props.getProperty(key, defaultValue);
    }

    public Object setProperty(String key, String value) {
        return this.props.setProperty(key, value);
    }
}

Méthode 5: Utilisation d'une classe utilitaire personnalisée PropertyUtil

package com.example.util;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.InputStream;
import java.util.Properties;

public class PropertyUtil {
    private static final Logger logger = LoggerFactory.getLogger(PropertyUtil.class);
    private static Properties props;

    static {
        loadProps();
    }

    synchronized static private void loadProps() {
        logger.info("Chargement des propriétés du fichier...");
        props = new Properties();
        InputStream in = null;
        try {
            in = PropertyUtil.class.getClassLoader().getResourceAsStream("jdbc.properties");
            props.load(in);
        } catch (Exception e) {
            logger.error("Erreur lors du chargement des propriétés", e);
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (Exception e) {
                    logger.error("Erreur lors de la fermeture du flux", e);
                }
            }
        }
        logger.info("Chargement des propriétés terminé.");
    }

    public static String getProperty(String key) {
        if (props == null) {
            loadProps();
        }
        return props.getProperty(key);
    }

    public static String getProperty(String key, String defaultValue) {
        if (props == null) {
            loadProps();
        }
        return props.getProperty(key, defaultValue);
    }
}

Conseils et précautions

Les trois premières méthodes sont moins flexibles et nécessitent des déclarations spécifiques dans les fichiers de configuration Spring ou SpringMVC. Les méthodes 4 et 5 sont plus efficaces et flexibles, notamment la méthode 5 qui ne nécesite pas d'injection d'objets et permet un chargement unique des propriétés.

Vérification des méthodes

  1. Créez l'interface PropertiesService:
package com.example.service;

public interface PropertiesService {
    String getPropertyByFirstWay();
    String getPropertyBySecondWay();
    String getPropertyByThirdWay();
    String getPropertyByFourthWay(String key);
    String getPropertyByFourthWay(String key, String defaultValue);
    String getPropertyByFifthWay(String key);
    String getPropertyByFifthWay(String key, String defaultValue);
}

  1. Implémentez l'interface PropertiesServiceImpl:
package com.example.service.impl;

import com.example.service.PropertiesService;
import com.example.util.CustomPropertyConfigurer;
import com.example.util.PropertyUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

@Service
public class PropertiesServiceImpl implements PropertiesService {

    @Value("${test}")
    private String testDataByFirst;

    @Value("#{prop.test}")
    private String testDataBySecond;

    @Value("#{propertiesReader[test]}")
    private String testDataByThird;

    @Autowired
    private CustomPropertyConfigurer pc;

    @Override
    public String getPropertyByFirstWay() {
        return testDataByFirst;
    }

    @Override
    public String getPropertyBySecondWay() {
        return testDataBySecond;
    }

    @Override
    public String getPropertyByThirdWay() {
        return testDataByThird;
    }

    @Override
    public String getPropertyByFourthWay(String key) {
        return pc.getProperty(key);
    }

    @Override
    public String getPropertyByFourthWay(String key, String defaultValue) {
        return pc.getProperty(key, defaultValue);
    }

    @Override
    public String getPropertyByFifthWay(String key) {
        return PropertyUtil.getProperty(key);
    }

    @Override
    public String getPropertyByFifthWay(String key, String defaultValue) {
        return PropertyUtil.getProperty(key, defaultValue);
    }
}

  1. Contrôleur PropertyController:
package com.example.controller;

import com.example.service.PropertiesService;
import com.example.util.PropertyUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
@RequestMapping("/prop")
public class PropertyController {
    @Autowired
    private PropertiesService ps;

    @RequestMapping(value = "/way/first", method = RequestMethod.GET)
    @ResponseBody
    public String getPropertyByFirstWay() {
        return ps.getPropertyByFirstWay();
    }

    @RequestMapping(value = "/way/second", method = RequestMethod.GET)
    @ResponseBody
    public String getPropertyBySecondWay() {
        return ps.getPropertyBySecondWay();
    }

    @RequestMapping(value = "/way/third", method = RequestMethod.GET)
    @ResponseBody
    public String getPropertyByThirdWay() {
        return ps.getPropertyByThirdWay();
    }

    @RequestMapping(value = "/way/fourth/{key}", method = RequestMethod.GET)
    @ResponseBody
    public String getPropertyByFourthWay(@PathVariable("key") String key) {
        return ps.getPropertyByFourthWay(key, "defaultValue");
    }

    @RequestMapping(value = "/way/fifth/{key}", method = RequestMethod.GET)
    @ResponseBody
    public String getPropertyByFifthWay(@PathVariable("key") String key) {
        return PropertyUtil.getProperty(key, "defaultValue");
    }
}

  1. Fichier jdbc.properties:
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://192.168.1.196:3306/dev?useUnicode=true&characterEncoding=UTF-8
jdbc.username=root
jdbc.password=123456
jdbc.maxActive=200
jdbc.minIdle=5
jdbc.initialSize=1
jdbc.maxWait=60000
jdbc.timeBetweenEvictionRunsMillis=60000
jdbc.minEvictableIdleTimeMillis=300000
jdbc.validationQuery=select 1 from t_user
jdbc.testWhileIdle=true
jdbc.testOnReturn=false
jdbc.poolPreparedStatements=true
jdbc.maxPoolPreparedStatementPerConnectionSize=20
jdbc.filters=stat
#test data
test=com.example

Conclusion

Ces méthodes permettent de mieux comprendre la relation entre les conteneurs parent et enfant de Spring et SpringMVC, ainsi que l'utilisation de l'attribut use-default-filters dans context:component-scan. Elles facilitent la résolution des problèmes liés aux configurations.

Étiquettes: Spring SpringMVC MyBatis PropertyPlaceholderConfigurer PropertiesFactoryBean

Publié le 7 septembre à 22h45