Propriétés en Java
Dans une application Java nous avons tous utilisé des fichiers properties. Par exemple application.properties
devmind.name=Dev-Mind
devmind.twitter=DevMind_FR
Pour lire le contenu du fichier, vous pouvez passer par la classe java.util.Propertiespublic class DevMindTest { Properties properties = new Properties(); { try { properties.load(getClass().getResourceAsStream("/application.properties")); } catch (IOException e) { e.printStackTrace(); } } @Test public void contextLoads() { Assertions.assertThat(
properties.getProperty("devmind.name")).isEqualTo("Dev-Mind"); } }
D'autres manières de passer des informations à un programme
En Java il existe également d'autres manières de passer des informations à un programme. Vous pouvez récupérer des valeurs définies dans des variables d'environnement
Assertions.assertThat(System.getenv("JAVA_HOME")).endsWith("/java/jdk1.8.0_40");
Mais aussi passer des arguments à votre programme.
public class SimpleMainApplication { public static void main(String[] args) { for (String arg : args) { System.out.println("Devmind app argument " + arg); } } }
La commande
java com.devmind.properties.SimpleMainApplication monarg1 monarg2
donnera
Devmind app argument monarg1
Devmind app argument monarg2
Il existe d'autres sources de données. Par exemple pour des ressources comme des bases de données ou autre nous pouvons définir des sources JNDI…
Spring et les fichiers properties
Avec Spring vous pouvez injecter directement des propriétés dans votre code via l'annotation @Value.
@Value("${devmind.name}") private String name;
Bien évidemment il faut que le fichier de ressources soit chargé. Mais si vous utilisez Spring Boot en respectant la convention (fichier nommé application.properties placé dans les ressources de votre application), vous pouvez importer directement des propriétés sans avoir à vous soucier de savoir comment les données sont chargées. Si ce n'est pas le cas vous pouvez spécifier les fichiers dont vous avez besoin dans un bean de configuration via l'annotation @PropertySource .
@Configuration@PropertySource("classpath:/monfichier.properties") public class DevMindConf { }
Spring apporte un niveau d'abstraction assez intéressant car la valeur que vous pouvez utiliser peut être une variable d'environnement, un argument de programme, une valeur définie dans un fichier….
Bien évidemment si une propriété est définie à plusieurs endroits, il existe un ordre de prise en compte et vous pouvez surcharger certaines propriétés. Ce mécanisme est très intéressant quand vous voulez personnaliser votre application sur un environnement. Dans une applicaton Spring Boot voici les possibilités
- Arguments passés à l'application
- Propriétés définies en JSON et stockées dans une variable d'environnement ou propriété système nommée SPRING_APPLICATION_JSON
- Attributs JNDI
- Propriétés systèmes JAVA
- Variable d'environnement de l'OS
- Fichiers de properties spécifiques à un environnement (voir un peu plus bas) définis en dehors d'un jar
- Fichiers de properties spécifiques à un environnement (voir un peu plus bas) packagés dans le jar de l'application
- Fichiers de properties définis en dehors d'un jar
- Fichiers de properties packagés dans le jar de l'application
- Fichiers définis via l'annotation @PropertySource dans vos beans de configuration
- Les propriétés par défaut définies via SpringApplication.setDefaultProperties
Le format YAML
Si vous en avez marre d'utiliser le format .properties et sa duplication de clé, vous pouvez opter pour le format YAML. Sa structure arborescente est à mon sens plus lisible. La classe SpringApplication gère ce format dès que vous avez la librairie SnakeYAML dans votre classpath. Avec SpringBoot c'est le cas et vous pouvez donc utiliser un fichier application.yml en lieu et place du traditionnel application.properties
devmind:
name: Dev-Mind twitter: DevMind_FR spring:
datasource:
driver-class-name: ${DATABASE_DRIVER:com.mysql.jdbc.Driver} username: ${DATABASE_USERNAME:devmind} password: ${DATABASE_PASSWORD:devmind}
Utiliser plusieurs propriétés dans vos services
Si vous avez besoin d'utiliser plusieurs propriétés et si vous injectez ces propriétés via @Value, votre composant peut vite devenir assez illisible. Vous pouvez donc directement injecter le bean de type Environment et utiliser les méthodes getProperty ou getRequiredProperty.
@Autowired
private Environment environment; public String getDevMindAdress() { return String.format("Society %s in city %s", environment.getRequiredProperty("devmind.name"), environment.getProperty("devmind.city", "Saint Etienne")); }
Au delà de la lisibilité cet artifice va également simplifier vos tests. Si vous utilisez par exemple Mockito vous pourrez facilement redéfinir les différentes valeurs des propriétés dans vos tests
public class DevMindServiceTest { @Rule
public MockitoRule rule = MockitoJUnit.rule(); @Mock
private Environment environment; @InjectMocks
private DevMindService devMindService; @Test
public void getDevMindAdress() { Mockito.when(environment.getRequiredProperty("devmind.name"))
.thenReturn("Dev-Mind"); Mockito.when(environment.getProperty("devmind.city", "Saint Etienne"))
.thenReturn("Lyon"); Assertions.assertThat(devMindService.getDevMindAdress())
.isEqualTo("Society Dev-Mind in city Lyon");
}
}
Une autre manière de faire est de regrouper vos paramètres dans des beans en utilisant l'annotation @ConfigurationProperties. Vous pourrez ensuite injecter ces beans à l'endroit où vous en avez besoin
@Component@ConfigurationProperties(prefix="devmind") public class DevMindConfiguration { private String name; private String twitter; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getTwitter() { return twitter; } public void setTwitter(String twitter) { this.twitter = twitter; } }
Avec Spring Boot le binding entre vos fichiers de configuration et ces beans est automatique. Pour une application Spring standard vous devrez ajouter l'annotation @EnableConfigurationProperties sur un de vos beans de configuration.
Cette solution est aussi intéressante quand vous utilisez les mêmes propriétés à plusieurs endroits dans votre code
Les profils
Dans une application Spring, vous pouvez utiliser les profils quand vous voulez spécifier des comportements différents en fonction des environnements. Vous définissez le ou les profils actifs au démarrage de votre application soit via des arguments ou une variable d'environnement nommée spring.profiles.active.
Au niveau des beans de configuration vous pouvez passer par l'annotation @Profile pour ne charger que certains beans dans des environnements donnés
@Configuration @Profile("production") public class DevMindConf { }
Au niveau de vos fichiers properties vous pouvez utiliser le nom du profile dans le nom des fichiers pour ne charger que ceux nécessaires.
application-{profile}.properties.
Comme nous l'avons vu un peu plus haut, les données définies dans ces fichiers surchargent celles définies dans le fichier application.properties qui contiendra tous vos paramètres par défaut et communs à tous les contextes.
Si vous faites du YAML vous pouvez personnaliser certaines valeurs liées à un profil directement dans le fichier application.yml en ajoutant des sections délimitées par ---.
devmind:
name: Dev-Mind
---
spring:
profiles: default
devmind:
city: Saint Etienne
---
spring:
profiles: cloud server:
port: 80
Je vais m'arrêter la dessus pour cette fois et j'espère que ces petites astuces vous aideront dans vos projets.
Aucun commentaire:
Enregistrer un commentaire
Remarque : Seul un membre de ce blog est autorisé à enregistrer un commentaire.