Я понимаю разницу между временем выполнения и временем компиляции и как их различать, но я просто не вижу необходимости проводить различие между зависимостями времени компиляции и времени выполнения.
Общие концепции времени компиляции и времени выполнения, а также зависимости Maven compileи runtimeобласти видимости - это две очень разные вещи. Вы не можете напрямую сравнивать их, поскольку у них разные рамки: общие концепции компиляции и времени выполнения широки, в то время как концепции maven compileи runtimescope касаются, в частности, доступности / видимости зависимостей в зависимости от времени: компиляция или выполнение.
Не забывайте, что Maven - это прежде всего javac/ javaоболочка, и что в Java у вас есть путь к классам времени компиляции, который вы указываете, javac -cp ... и путь к классам времени выполнения, который вы указываете java -cp ....
Было бы правильно рассматривать область Maven compileкак способ добавления зависимости как в компиляцию Java, так и в runtime classppath (javacи java), в то время как область Maven runtimeможно рассматривать как способ добавления зависимости только в среде выполнения Java classppath ( javac).
Я задыхаюсь от этого: как программа может не зависеть во время выполнения от чего-то, от чего она зависела во время компиляции?
То , что вы описали не имеет никакого отношения с runtimeи compileобъемом.
Похоже, что providedобласть видимости, которую вы указываете, зависит от зависимости во время компиляции, но не во время выполнения.
Вы используете его, поскольку вам нужна зависимость для компиляции, но вы не хотите включать ее в упакованный компонент (JAR, WAR или любой другой), потому что зависимость уже предоставлена средой: она может быть включена в сервер или любой другой путь к пути к классам, указанному при запуске приложения Java.
Если мое приложение Java использует log4j, то ему нужен файл log4j.jar для компиляции (мой код интегрируется с методами-членами и вызывает их изнутри log4j), а также во время выполнения (мой код не имеет абсолютно никакого контроля над тем, что происходит, когда код внутри log4j .jar запущен).
В этом случае да. Но предположим, что вам нужно написать переносимый код, который полагается на slf4j в качестве фасада перед log4j, чтобы иметь возможность позже переключиться на другую реализацию ведения журнала (log4J 2, logback или любую другую).
В этом случае в вашем pom вам нужно указать slf4j как compileзависимость (это значение по умолчанию), но вы укажете зависимость log4j как runtimeзависимость:
<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>
Таким образом, на классы log4j нельзя ссылаться в скомпилированном коде, но вы все равно сможете ссылаться на классы slf4j.
Если вы указали две зависимости со compileвременем, ничто не помешает вам ссылаться на классы log4j в скомпилированном коде, и вы можете создать нежелательную связь с реализацией ведения журнала:
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>...</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>...</version>
</dependency>
Обычно runtimeобласть видимости используется в объявлении зависимости JDBC. Чтобы писать переносимый код, вы не хотите, чтобы клиентский код мог ссылаться на классы конкретной зависимости СУБД (например, зависимость PostgreSQL JDBC), но вы все равно хотите включить его в свое приложение, поскольку во время выполнения классы необходимы для создания JDBC API работает с этой СУБД.