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