Skip to content

Travailler avec des dépendances

Pendant l'écriture et le débogage de notre application, il peut être tentant d'utiliser beaucoup de System.out.println pour imprimer la trace d'exécution, pour "voir où cela commence à échouer".

// ...
if (user == null) {
    if (enableDebug) {
        System.out.println("foo 1")
        System.out.println("Error: user is null")
    }
    // ...
}

C'est une très mauvaise façon de créer des logs :

  • Elle alourdit à la fois le code et la sortie.
  • Cela ralentit l'exécution du programme.
  • Vous oublierez de les supprimer après le débogage, ce qui entraînera beaucoup de bruit dans le code.

Pour faciliter le débogage de votre code, il est préférable d'utiliser un Logger car :

  • Il existe plusieurs niveaux de log (DEBUG, INFO, WARN, ERROR). Vous pouvez donc choisir celui qui convient le mieux à votre environnement (ex : INFO pour les besoins de production, DEBUG pour les environnements de développement...)
  • Il peut écrire les logs dans un fichier plutôt que dans la console.
  • Il est indépendant de la plateforme.
  • Il offre de meilleures performances avec des flux tamponnés.
  • Il permet aux bibliothèques installées de logger avec votre Logger afin d'éviter l'encombrement de plusieurs loggers.

Dans ce chapitre, nous utiliserons l'API de journalisation SLF4J.

SLF4J

Installez SLF4J

  • Ajoutez la dernière version de slf4j-api dans la partie dependencies du fichier pom.xml.
Afficher le pom.xml résultant
  <project>
    <dependencies>
      <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>2.0.6</version>
      </dependency>
    </dependencies>
  </project>

tip

  • Lorsque vous cherchez une bibliothèque Maven, ne cherchez pas sur Google. Parcourez simplement Maven central.
  • Si vous utilisez un IDE comme Intellij, lancez la synchronisation des dépendances Maven lorsque vous ajoutez de nouvelles dépendances, pour lui permettre de vous donner les bonnes suggestions d'importation.

Utilisez SLF4J

  • Modifiez App.java et réécrivez le message initial Hello world ! pour utiliser le logger.
app.java
package io.takima.agencymanagement;

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

public class App {
    private static final Logger LOGGER = LoggerFactory.getLogger(App.class);

    public static void main(String[] args) {
        LOGGER.info("Hello World!");
    }
}
  • Lancez le code :

Failure

SLF4J: No SLF4J providers were found.
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See https://www.slf4j.org/codes.html#noProviders for further details.

Comme l'indique l'erreur, SLF4J a besoin d'une implémentation. slf4j-api est seulement une API qui ne fait donc rien par elle-même : elle s'appuie sur d'autres dépendances pour implémenter les fonctionnalités de logging. Dans ce chapitre, nous utiliserons slf4j-log4j12 comme implémentation pour SLF4J.

Installez et configurez log4j

  • Ajoutez slf4j-log4j12 dans la partie dependencies du fichier pom.xml.
Afficher le pom.xml résultant
<project>
  <dependencies>
    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-log4j12</artifactId>
      <version>2.0.6</version>
    </dependency>
  </dependencies>
</project>

Info

Certaines dépendances peuvent avoir des versions alignées (ex : slf4j-log4j12 avec slf4j-api). Pour les garder alignées et éviter le copier-coller, c'est une bonne pratique d'utiliser <properties> au-dessus du pom.xml pour déclarer les versions comme des variables.

pom.xml
<properties>
   <java.version>17</java.version>
   <maven.compiler.source>${java.version}</maven.compiler.source>
   <maven.compiler.target>${slf4j.version}</maven.compiler.target>
   <slf4j.version>2.0.6</slf4j.version>
 </properties>
 <dependencies>
   <dependency>
     <groupId>org.slf4j</groupId>
     <artifactId>slf4j-log4j12</artifactId>
     <version>${slf4j.version}</version>
   </dependency>
   <dependency>
     <groupId>org.slf4j</groupId>
     <artifactId>slf4j-api</artifactId>
     <version>${slf4j.version}</version>
   </dependency>
 </dependencies>

Configurez Log4j

  • Créez un dossier dans src/main/resources s'il n'existe pas.
  • Mettez-y un nouveau fichier appelé log4j.properties, avec la configuration suivante.
  log4j.rootLogger=DEBUG, stdout

  log4j.appender.stdout=org.apache.log4j.ConsoleAppender
  log4j.appender.stdout.Target=System.out
  log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
  log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n
  • Exécutez à nouveau le code. Cette fois, le journal devrait apparaître sur la sortie standard :
INFO  App:14 - Hello World!
Error: No SLF4J providers were found.

Vous avez à nouveau cette erreur ?

Avez-vous correctement défini le <scope> à compile pour la dépendance slf4j-log4j12 ?

Exécutez sans IDE

Dans cette étape, nous allons compiler et exécuter le code sans avoir besoin d'un IDE.

mvn clean package
java -jar target/takima-agencymanagement-1.0-SNAPSHOT.jar

Failure

Exception in thread "main" java.lang.NoClassDefFoundError: org/slf4j/LoggerFactory
        at io.takima.agencymanagement.App.<clinit>(App.java:11)
Caused by: java.lang.ClassNotFoundException: org.slf4j.LoggerFactory
        at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641)
        at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
        at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
        ... 1 more

Une autre erreur d'exécution. Cette fois, Java exécute le jar, mais notre application dépend d'une dépendance externe org/slf4j/LoggerFactory. Parce que cette dépendance est gérée par Maven, elle a été installée dans votre dépôt local .m2. Cependant, Java ne va pas automatiquement y chercher des classes supplémentaires, d'où l'erreur.

Pour activer cette dépendance, vous devez configurer le classpath de la JVM avec l'option java -classpath. Dans l'étape suivante, nous allons explorer une technique appelée fat JAR.

Fat JAR

Un fat JAR, également appelé uber JAR, ou jar-with-dependencies, est un jar qui regroupe toutes les dépendances nécessaires, de sorte que l'application ne dépende pas des dépendances installées localement.

Ce type de jar peut être construit avec l'aide de maven-assembly-plugin.

Info

  • Un fat JAR ne nécessite pas de configurer le CLASSPATH.
  • Un fat JAR a une taille plus importante que les JARs normaux.
  • Editez le pom.xml et ajoutez ou remplacez le maven-jar-plugin existant, avec la configuration suivante :
<!-- Maven Assembly Plugin -->
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-assembly-plugin</artifactId>
    <configuration>
        <!-- get all project dependencies -->
        <descriptorRefs>
            <descriptorRef>jar-with-dependencies</descriptorRef>
        </descriptorRefs>
        <!-- MainClass in manifest make a jar executable -->
        <archive>
            <manifest>
                <mainClass>io.takima.agencymanagement.App</mainClass>
            </manifest>
        </archive>
    </configuration>
    <executions>
        <execution>
            <id>make-assembly</id>
            <!-- bind to the packaging phase -->
            <phase>package</phase>
            <goals>
                <goal>single</goal>
            </goals>
        </execution>
    </executions>
</plugin>
  • Créez à nouveau le paquet, puis exécutez le fichier *-with-dependencies.jar.
mvn clean package assembly:single
java -jar target/takima-agencymanagement-1.0-SNAPSHOT-jar-with-dependencies.jar
Le jar-with-dependencies n'est pas généré ?

Il se peut que vous deviez supprimer la balise pluginManagement dans le fichier pom.xml.

Fichiers modifiés

src/main/java/io/takima/agencymanagement/App.java
src/main/resources/log4j.{properties|xml}

N'oubliez pas de Commit votre travail !