Capisco la differenza tra runtime e compilazione e come distinguere tra i due, ma non vedo la necessità di fare una distinzione tra le dipendenze in fase di compilazione e in runtime.
I concetti generali in fase di compilazione e runtime e le dipendenze specifiche compile
e di runtime
ambito di Maven sono due cose molto diverse. Non è possibile confrontarli direttamente poiché questi non hanno lo stesso frame: i concetti generali di compilazione e runtime sono ampi mentre i concetti di maven compile
e runtime
scope riguardano specificamente la disponibilità / visibilità delle dipendenze in base al tempo: compilazione o esecuzione.
Non dimenticare che Maven è soprattutto un javac
/ java
wrapper e che in Java hai un classpath in fase di compilazione che specifichi con javac -cp ...
e un classpath runtime che specifichi con java -cp ...
.
Non sarebbe sbagliato considerare l' compile
ambito Maven come un modo per aggiungere una dipendenza sia nella compilazione Java che nel percorso di classe runtime (javac
e java
) mentre l' runtime
ambito Maven può essere visto come un modo per aggiungere una dipendenza solo nel classppath ( javac
) del runtime Java .
Quello su cui sto soffocando è questo: come può un programma non dipendere da qualcosa in fase di esecuzione da cui dipendeva durante la compilazione?
Ciò che descrivi non ha alcuna relazione runtime
e compile
scopo.
Sembra più l' provided
ambito specificato per una dipendenza da dipendere da quello in fase di compilazione ma non in fase di runtime.
Lo usi perché ti serve la dipendenza da compilare ma non vuoi includerlo nel componente pacchettizzato (JAR, WAR o qualsiasi altro) perché la dipendenza è già fornita dall'ambiente: può essere inclusa nel server o in qualsiasi altro percorso del classpath specificato all'avvio dell'applicazione Java.
Se la mia app Java utilizza log4j, ha bisogno del file log4j.jar per compilare (il mio codice si integra e richiama i metodi dei membri dall'interno di log4j) così come il runtime (il mio codice non ha assolutamente alcun controllo su ciò che accade una volta che il codice si trova all'interno di log4j .jar è eseguito).
In questo caso sì. Ma supponiamo di dover scrivere un codice portabile che si basi su slf4j come facciata davanti a log4j per poter passare successivamente a un'altra implementazione di registrazione (log4J 2, logback o qualsiasi altra).
In questo caso in te pom devi specificare slf4j come compile
dipendenza (è l'impostazione predefinita) ma specificherai la dipendenza log4j come runtime
dipendenza:
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>...</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>...</version>
<scope>runtime</scope>
</dependency>
In questo modo, non è stato possibile fare riferimento alle classi log4j nel codice compilato ma sarà comunque possibile fare riferimento alle classi slf4j.
Se hai specificato le due dipendenze con l' compile
ora, nulla ti impedirà di fare riferimento alle classi log4j nel codice compilato e potresti quindi creare un accoppiamento indesiderato con l'implementazione del logging:
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>...</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>...</version>
</dependency>
Un utilizzo comune runtime
dell'ambito è la dichiarazione di dipendenza JDBC. Per scrivere codice portabile, non si desidera che il codice client faccia riferimento a classi della dipendenza DBMS specifica (ad esempio: dipendenza JDBC PostgreSQL) ma si desidera comunque includerlo nella propria applicazione poiché a runtime le classi sono necessarie per creare l'API JDBC funziona con questo DBMS.