Я понимаю разницу между временем выполнения и временем компиляции и как различать их, но я просто не вижу необходимости проводить различие между зависимостями времени компиляции и времени выполнения .
Я задыхаюсь от этого: как программа может не зависеть во время выполнения от чего-то, от чего она зависела во время компиляции? Если мое приложение Java использует log4j, то ему нужен файл log4j.jar для компиляции (мой код интегрируется с методами-членами и вызывает их изнутри log4j), а также во время выполнения (мой код не имеет абсолютно никакого контроля над тем, что происходит, когда код внутри log4j .jar запущен).
Я читаю об инструментах разрешения зависимостей, таких как Ivy и Maven, и эти инструменты четко различают эти два типа зависимостей. Я просто не понимаю, зачем это нужно.
Может ли кто-нибудь дать простое объяснение типа «королевского английского», желательно с реальным примером, который мог бы понять даже такой бедняк, как я?
источник
Ответы:
Зависимость времени компиляции обычно требуется во время выполнения. В maven
compile
зависимость с определенным диапазоном будет добавлена в путь к классам во время выполнения (например, в войнах они будут скопированы в WEB-INF / lib).Однако это не обязательно; например, мы можем скомпилировать определенный API, сделав его зависимостью во время компиляции, но затем во время выполнения включить реализацию, которая также включает API.
Могут быть отдельные случаи, когда проекту требуется определенная зависимость для компиляции, но тогда соответствующий код на самом деле не нужен, но они будут редкими.
С другой стороны, очень распространено включение зависимостей времени выполнения, которые не нужны во время компиляции. Например, если вы пишете приложение Java EE 6, вы компилируете с использованием API Java EE 6, но во время выполнения можно использовать любой контейнер Java EE; именно этот контейнер обеспечивает реализацию.
Зависимостей времени компиляции можно избежать, используя отражение. Например, драйвер JDBC можно загрузить с помощью a,
Class.forName
а фактический загруженный класс можно настроить с помощью файла конфигурации.источник
provided
область действия добавляет зависимость времени компиляции без добавления зависимости времени выполнения от ожидания того, что зависимость будет обеспечиваться во время выполнения другими средствами (например, разделяемой библиотекой в контейнере).runtime
с другой стороны, добавляет зависимость времени выполнения, не делая ее зависимостью времени компиляции.Каждая зависимость Maven имеет область, определяющую, для какого пути к классам эта зависимость доступна.
Когда вы создаете JAR для проекта, зависимости не связываются с сгенерированным артефактом; они используются только для компиляции. (Однако вы все равно можете заставить maven включать зависимости во встроенную банку, см .: Включение зависимостей в банку с помощью Maven )
Когда вы используете Maven для создания файла WAR или EAR, вы можете настроить Maven для связывания зависимостей с сгенерированным артефактом, а также можете настроить его для исключения определенных зависимостей из файла WAR с использованием предоставленной области.
Наиболее распространенная область видимости - Compile Scope - указывает, что зависимость доступна для вашего проекта в пути к классам компиляции, в путях к классам компиляции и выполнения модульного теста и в конечном пути к классам времени выполнения при выполнении приложения. В веб-приложении Java EE это означает, что зависимость копируется в развернутое приложение. Однако в файле .jar зависимости не будут включены в область компиляции.
Область выполнения указывает, что для вашего проекта доступна зависимость от путей к классам выполнения модульного теста и выполнения во время выполнения, но, в отличие от области компиляции, она недоступна при компиляции приложения или его модульных тестов. Зависимость времени выполнения копируется в развернутое приложение, но недоступна во время компиляции! Это хорошо для того, чтобы убедиться, что вы по ошибке не зависите от конкретной библиотеки.
Наконец, Provided Scope указывает, что контейнер, в котором выполняется ваше приложение, предоставляет зависимость от вашего имени. В приложении Java EE это означает, что зависимость уже находится в пути к классам контейнера сервлета или сервера приложений и не копируется в развернутое приложение. Это также означает, что вам нужна эта зависимость для компиляции вашего проекта.
источник
Вам понадобятся зависимости во время компиляции, которые могут вам понадобиться во время выполнения. Однако многие библиотеки работают без всех возможных зависимостей. т.е. библиотеки, которые могут использовать четыре разные библиотеки XML, но для работы нужна только одна.
Многим библиотекам в свою очередь нужны другие библиотеки. Эти библиотеки не нужны во время компиляции, но необходимы во время выполнения. т.е. когда код действительно выполняется.
источник
В общем, вы правы и, вероятно, это идеальная ситуация, если зависимости времени выполнения и времени компиляции идентичны.
Я приведу вам 2 примера, когда это правило неверно.
Если класс A зависит от класса B, который зависит от класса C, который зависит от класса D, где A - ваш класс, а B, C и D - классы из разных сторонних библиотек, вам нужны только B и C во время компиляции, и вам также нужно D на время выполнения. Часто программы используют динамическую загрузку классов. В этом случае вам не нужны классы, динамически загружаемые библиотекой, которую вы используете во время компиляции. Более того, часто библиотека выбирает, какую реализацию использовать во время выполнения. Например, SLF4J или Commons Logging могут изменить реализацию целевого журнала во время выполнения. Во время компиляции вам понадобится только сам SSL4J.
Противоположный пример, когда вам нужно больше зависимостей во время компиляции, чем во время выполнения. Представьте, что вы разрабатываете приложение, которое должно работать в разных средах или операционных системах. Вам понадобятся все библиотеки для конкретной платформы во время компиляции и только библиотеки, необходимые для текущей среды во время выполнения.
Надеюсь, мои объяснения помогут.
источник
Обычно статический граф зависимостей является подграфом динамического, см., Например, эту запись в блоге автора NDepend .
Тем не менее, есть некоторые исключения, в основном зависимости, которые добавляют поддержку компилятора, которая становится невидимой во время выполнения. Например, для генерации кода через Lombok или дополнительных проверок через Checker Framework (подключаемый тип) .
источник
Только что столкнулся с проблемой, которая отвечает на ваш вопрос.
servlet-api.jar
является временной зависимостью в моем веб-проекте и требуется как во время компиляции, так и во время выполнения. Ноservlet-api.jar
он также включен в мою библиотеку Tomcat.Решение здесь состоит в том, чтобы сделать
servlet-api.jar
maven доступным только во время компиляции и не упаковывать в мой военный файл, чтобы он не конфликтовал сservlet-api.jar
содержимым моей библиотеки Tomcat.Я надеюсь, что это объясняет зависимость времени компиляции и времени выполнения.
источник
compile
иprovided
оптическими прицелами и не междуcompile
иruntime
.Compile scope
необходимы во время компиляции и упакованы в ваше приложение.Provided scope
требуется только во время компиляции, но не упакован в ваше приложение, потому что он предоставляется другими средствами, например, он уже находится на сервере Tomcat.compile
иruntime
областей применения maven . Областьprovided
видимости - это способ, которым maven обрабатывает случай, когда зависимость времени компиляции не должна быть включена в пакет времени выполнения.Общие концепции времени компиляции и времени выполнения, а также зависимости Maven
compile
иruntime
области видимости - это две очень разные вещи. Вы не можете напрямую сравнивать их, поскольку у них разные рамки: общие концепции компиляции и времени выполнения широки, в то время как концепции mavencompile
иruntime
scope касаются, в частности, доступности / видимости зависимостей в зависимости от времени: компиляция или выполнение.Не забывайте, что Maven - это прежде всего
javac
/java
оболочка, и что в Java у вас есть путь к классам времени компиляции, который вы указываете,javac -cp ...
и путь к классам времени выполнения, который вы указываетеjava -cp ...
.Было бы правильно рассматривать область Maven
compile
как способ добавления зависимости как в компиляцию Java, так и в runtime classppath (javac
иjava
), в то время как область Mavenruntime
можно рассматривать как способ добавления зависимости только в среде выполнения Java classppath (javac
).То , что вы описали не имеет никакого отношения с
runtime
иcompile
объемом.Похоже, что
provided
область видимости, которую вы указываете, зависит от зависимости во время компиляции, но не во время выполнения.Вы используете его, поскольку вам нужна зависимость для компиляции, но вы не хотите включать ее в упакованный компонент (JAR, WAR или любой другой), потому что зависимость уже предоставлена средой: она может быть включена в сервер или любой другой путь к пути к классам, указанному при запуске приложения Java.
В этом случае да. Но предположим, что вам нужно написать переносимый код, который полагается на slf4j в качестве фасада перед log4j, чтобы иметь возможность позже переключиться на другую реализацию ведения журнала (log4J 2, logback или любую другую).
В этом случае в вашем pom вам нужно указать slf4j как
compile
зависимость (это значение по умолчанию), но вы укажете зависимость log4j какruntime
зависимость:Таким образом, на классы log4j нельзя ссылаться в скомпилированном коде, но вы все равно сможете ссылаться на классы slf4j.
Если вы указали две зависимости со
compile
временем, ничто не помешает вам ссылаться на классы log4j в скомпилированном коде, и вы можете создать нежелательную связь с реализацией ведения журнала:Обычно
runtime
область видимости используется в объявлении зависимости JDBC. Чтобы писать переносимый код, вы не хотите, чтобы клиентский код мог ссылаться на классы конкретной зависимости СУБД (например, зависимость PostgreSQL JDBC), но вы все равно хотите включить его в свое приложение, поскольку во время выполнения классы необходимы для создания JDBC API работает с этой СУБД.источник
Во время компиляции вы включаете контракты / api, которые ожидаются от ваших зависимостей. (например: здесь вы просто подписываете контракт с провайдером широкополосного доступа в Интернет) Фактически во время выполнения вы используете зависимости. (например: здесь вы фактически используете широкополосный доступ в Интернет)
источник
Чтобы ответить на вопрос «как программа может не зависеть во время выполнения от чего-то, от чего она зависела во время компиляции?», Давайте рассмотрим пример процессора аннотаций.
Предположим, вы написали свой собственный обработчик аннотаций, и предположим, что он имеет зависимость во время компиляции,
com.google.auto.service:auto-service
так что он может использовать@AutoService
. Эта зависимость требуется только для компиляции процессора аннотаций, но не требуется во время выполнения: все другие проекты, зависящие от вашего процессора аннотаций для обработки аннотаций, не требуют зависимости отcom.google.auto.service:auto-service
во время выполнения (ни во время компиляции, ни в любое другое время) .Это не очень часто, но бывает.
источник
Эта
runtime
область предназначена для предотвращения добавления программистами прямых зависимостей к библиотекам реализации в коде вместо использования абстракций или фасадов.Другими словами, он заставляет использовать интерфейсы.
Конкретные примеры:
1) Ваша команда использует SLF4J вместо Log4j. Вы хотите, чтобы ваши программисты использовали API SLF4J, а не Log4j. Log4j должен использоваться SLF4J только для внутренних целей. Решение:
2) Ваше приложение обращается к MySQL с помощью JDBC. Вы хотите, чтобы ваши программисты использовали код стандартной абстракции JDBC, а не напрямую против реализации драйвера MySQL.
mysql-connector-java
(драйвер MySQL JDBC) как зависимость времени выполнения.Зависимости времени выполнения скрыты во время компиляции (выдают ошибки времени компиляции, если ваш код имеет «прямую» зависимость от них), но включаются во время выполнения и при создании развертываемых артефактов (файлы WAR, файлы JAR SHADED и т. Д.).
источник