Eu entendo a diferença entre tempo de execução e tempo de compilação e como diferenciá-los, mas simplesmente não vejo a necessidade de fazer uma distinção entre dependências de tempo de compilação e tempo de execução.
Os conceitos gerais de tempo de compilação e tempo de execução e as dependências específicas compile
e de runtime
escopo do Maven são duas coisas muito diferentes. Você não pode compará-los diretamente, já que eles não têm o mesmo quadro: os conceitos gerais de compilação e tempo de execução são amplos, enquanto os conceitos de maven compile
e runtime
escopo tratam especificamente da disponibilidade / visibilidade das dependências de acordo com o tempo: compilação ou execução.
Não se esqueça de que Maven é acima de tudo um javac
/ java
wrapper e que em Java você tem um classpath de tempo de compilação que você especifica com javac -cp ...
e um classpath de tempo de execução que você especifica com java -cp ...
.
Não seria errado considerar o compile
escopo do Maven como uma forma de adicionar uma dependência na compilação Java e no classppath do runtime (javac
e java
) enquanto o runtime
escopo Maven pode ser visto como uma forma de adicionar uma dependência apenas no classppath do Java runtime ( javac
).
O que estou engasgando é o seguinte: como um programa pode não depender de algo em tempo de execução de que dependia durante a compilação?
O que você descreve não tem nenhuma relação com runtime
e compile
escopo.
Parece mais para o provided
escopo que você especifica para uma dependência depender disso em tempo de compilação, mas não em tempo de execução.
Você o usa porque precisa da dependência para compilar, mas não quer incluí-lo no componente empacotado (JAR, WAR ou qualquer outro) porque a dependência já é fornecida pelo ambiente: pode ser incluída no servidor ou em qualquer caminho do caminho de classe especificado quando o aplicativo Java é iniciado.
Se meu aplicativo Java usa log4j, ele precisa do arquivo log4j.jar para compilar (meu código se integra e invoca métodos de membro de dentro de log4j), bem como o tempo de execução (meu código não tem absolutamente nenhum controle sobre o que acontece quando o código está dentro de log4j .jar é executado).
Neste caso sim. Mas suponha que você precise escrever um código portátil que dependa do slf4j como fachada na frente do log4j para poder alternar para outra implementação de registro posteriormente (log4J 2, logback ou qualquer outro).
Neste caso, em seu pom, você precisa especificar slf4j como uma compile
dependência (é o padrão), mas você especificará a dependência log4j como uma runtime
dependência:
<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>
Dessa forma, as classes log4j não puderam ser referenciadas no código compilado, mas você ainda poderá fazer referência às classes slf4j.
Se você especificou as duas dependências com o compile
tempo, nada o impedirá de fazer referência a classes log4j no código compilado e você poderá criar um acoplamento indesejável com a implementação de registro:
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>...</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>...</version>
</dependency>
Um uso comum de runtime
escopo é a declaração de dependência JDBC. Para escrever código portátil, você não quer que o código do cliente se refira a classes da dependência DBMS específica (por exemplo: dependência PostgreSQL JDBC), mas você quer mesmo incluí-lo em seu aplicativo como no tempo de execução as classes são necessárias para fazer a API JDBC funciona com este DBMS.