Как работают необязательные зависимости времени компиляции? - PullRequest
4 голосов
/ 25 января 2020

Долгое время я думал, что в Java у вас есть один из двух типов зависимостей:

  • Обязательные зависимости во время компиляции (зависимости всегда требуются во время компиляции)
  • Возможно, необязательные зависимости времени выполнения (зависимости, которые можно разрешить во время выполнения)

Недавно я обнаружил, что зависимости компиляции тоже могут быть необязательными. Например, commons-beanutils указан как необязательная зависимость компиляции из JXPath.

Как это может работать? Может ли зависимость действительно использоваться во время компиляции, но при этом оставаться полностью необязательной?

РЕДАКТИРОВАТЬ: Я мог бы быть неясным. Я ищу случай, когда зависимость используется во время компиляции и в то же время является полностью необязательной, или объяснение, почему такая зависимость невозможна.

Ответы [ 3 ]

3 голосов
/ 26 января 2020

Класс может компилироваться в интерфейс, но реализация этого интерфейса не требуется во время компиляции. Реализация необходима во время выполнения.

Пример ведения общего журнала, JPA, JDB C et c, которые являются платформами, приложение может компилировать на их основе. Во время выполнения необходима реализация для выполнения кода. Примеры реализации - утилиты Common Bean, тонкий драйвер Oracle, Eclipse link et c.

1 голос
/ 26 января 2020

Обширная цитата из Документации Maven описывает это довольно четко:

Дополнительные зависимости используются, когда невозможно (по какой-либо причине) разделить проект на подмодули. , Идея заключается в том, что некоторые зависимости используются только для определенных функций проекта и не понадобятся, если эта функция не используется. В идеале такая функция должна быть разбита на подмодуль, который зависит от проекта основной функциональности. Этот новый подпроект будет иметь только необязательные зависимости, так как они вам понадобятся, если вы решите использовать функциональность подпроекта.

Однако, поскольку проект не может быть разделен (опять же, по какой-либо причине), эти зависимости объявлены необязательными. Если пользователь хочет использовать функциональность, связанную с необязательной зависимостью, он должен повторно объявить эту необязательную зависимость в своем собственном проекте. Это не самый ясный способ справиться с этой ситуацией, но и необязательные зависимости, и исключения из зависимостей являются решениями с ограничением.

Зачем использовать необязательные зависимости?

Необязательные зависимости экономят место и память. Они предотвращают создание проблемных c файлов jar, которые нарушают лицензионное соглашение или приводят к тому, что проблемы с classpath объединяются в WAR, EAR, fat jar и т. П.

Как работают необязательные зависимости?

Project-A -> Project-B

Диаграмма выше говорит о том, что Project-A зависит от Project-B. Когда A объявляет B как необязательную зависимость в своем POM, это отношение остается неизменным. Это похоже на нормальную сборку, в которой Project-B будет добавлен в путь к классам Project-A.

Project-X -> Project-A

Когда другой проект (Project-X) объявляет Project-A как зависимость в своем POM, необязательный характер зависимости вступает в силу. Project-B не включен в путь к классу Project-X. Вам нужно объявить это непосредственно в POM Project X для B, чтобы включить его в classpath X.

Практический пример: представьте, что вы разработчик библиотеки / фреймворка SuperLib, который построен как один superlib.jar. Ваша библиотека предоставляет несколько функций. Его основная функция (которую использует большинство пользователей) - внедрение зависимостей на основе сторонней библиотеки di. Тем не менее, один из ваших классов - EmailApi - предлагает функции для отправки электронной почты, используя стороннюю библиотеку email. Поскольку superlib является одним артефактом, для компиляции требуется di и email.

Теперь поставьте себя на место пользователя, который использует superlib. Их интересуют особенности внедрения зависимостей. Это основная роль вашей библиотеки, поэтому зависимость между superlib и di будет , а не необязательной.

Однако большинство пользователей не заинтересованы в отправке электронных писем и могут беспокоит наличие бесполезной библиотеки email и ее зависимостей, добавленных в их приложение (что приведет к увеличению размера их приложения и может вызвать версию зависимости cla sh между зависимостями email и зависимостями приложения пользователя). Следовательно, вы должны пометить зависимость от email как optional. Пока пользователь не использует ваш класс EmailApi, все будет работать нормально. Однако, если они используют EmailApi, им потребуется зависимость email, в противном случае приложение завершится с ошибкой во время выполнения с ClassNotFoundException для любого класса из email, на который будет ссылаться в EmailApi. Пользователю вашей библиотеки необходимо явно добавить зависимость email в свой POM.

См. Также Когда использовать <optional>true</optional> и когда использовать <scope>provided</scope>.

0 голосов
/ 26 января 2020

То, что вы описали, на самом деле является функцией Maven, инструмента для сборки, но не Java. Без инструментов сборки, используя просто 'javac', вам нужно указать все классы или интерфейсы, которые непосредственно используются в вашем коде. Конечно, есть варианты для загрузки классов Dynami c и даже для компиляции во время выполнения, но это не относится к topi c.

Один из вариантов использования с разделением на интерфейс и реализацию описан в предыдущем ответе, другой популярный case основан на сканировании пути к классам: если какой-либо указанный класс c присутствует в classpath и / или имеет конкретную аннотацию c - будет загружен дополнительный модуль.

Вот так загружаются модули Spring Boot.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...