JEP 260: Encapsulate Most Internal APIs
Инкапсуляция большинства внутренних API
| Автор | Mark Reinhold |
| Ответственный | Chris Hegarty |
| Тип | Feature |
| Область | JDK |
| Статус | Closed / Delivered |
| Выпуск | 9 |
| Обсуждение | jigsaw dash dev at openjdk dot java dot net |
| Трудоёмкость | M |
| Длительность | L |
| Блокирует | JEP 261: Module System |
| Связан с | JEP 396: Strongly Encapsulate JDK Internals by Default |
| JEP 403: Strongly Encapsulate JDK Internals | |
| Рецензенты | Alan Bateman, Alex Buckley, Brian Goetz, John Rose, Paul Sandoz |
| Одобрен | Brian Goetz |
| Создан | 2015/08/03 18:29 |
| Обновлён | 2024/04/28 18:11 |
| Задача | 8132928 |
Аннотация
По умолчанию инкапсулировать большинство внутренних API JDK, чтобы они были недоступны во время компиляции, и подготовиться к будущему выпуску, в котором они будут недоступны и во время выполнения. Обеспечить, чтобы критически важные и широко используемые внутренние API не инкапсулировались и оставались доступными, пока для всей или большей части их функциональности не появятся поддерживаемые замены.
Что не является целью
Этот JEP не определяет замены ни для каких внутренних API: этим занимаются или будут заниматься отдельные JEP и, где это уместно, JSR.
Этот JEP не обязуется сохранять совместимость каких-либо внутренних API между выпусками: они по-прежнему остаются нестабильными и могут меняться без предупреждения.
Мотивация
Некоторые популярные библиотеки используют нестандартные, нестабильные и неподдерживаемые API, которые являются внутренними деталями реализации JDK и никогда не предназначались для внешнего использования. В модульном JDK (JEP 200) ограничение доступа к этим API средствами модульной системы (JEP 261) повышает целостность и безопасность платформы, поскольку многие из этих внутренних API определяют привилегированные операции, важные для безопасности. В долгосрочной перспективе это изменение снизит затраты тех, кто сопровождает сам JDK, а также тех, кто сопровождает библиотеки и приложения, которые, сознательно или нет, используют эти внутренние API.
Описание
На основе анализа различных больших массивов кода, включая Maven Central, а также отзывов, полученных после выхода JDK 8 и его инструмента анализа зависимостей (jdeps), мы делим внутренние API JDK на две большие категории:
-
Некритичные внутренние API, которые, по-видимому, не используются кодом за пределами JDK или используются внешним кодом лишь для удобства, т. е. ради функциональности, которая есть в поддерживаемых API или легко может быть предоставлена библиотеками (например,
sun.misc.BASE64Decoder); и -
Критически важные внутренние API (например,
sun.misc.Unsafe), которые предоставляют критически важную функциональность, которую было бы трудно, если не невозможно, реализовать вне самого JDK.
Критически важные внутренние API в JDK 9 инкапсулируются или нет в зависимости от того, существуют ли для них поддерживаемые замены в JDK 8. Поддерживаемая замена — это API, который либо входил в стандарт Java SE 8, т. е. находился в пакете java.* или javax.*, либо был специфичен для JDK и помечен аннотацией @jdk.Exported, обычно в пакете com.sun.* или jdk.*. Подробнее:
-
Критически важные внутренние API, для которых в JDK 8 существуют поддерживаемые замены, в JDK 9 инкапсулированы.
-
Критически важные внутренние API, для которых в JDK 8 не было поддерживаемых замен, в JDK 9 не инкапсулированы. Подробный список приведён ниже.
-
Критически важные внутренние API, для которых в JDK 9 существуют поддерживаемые замены, помечены как Deprecated (устаревший) и в будущем выпуске будут либо инкапсулированы, либо удалены.
Все некритичные внутренние API в JDK 9 инкапсулированы.
Внутренние API, инкапсулированные в JDK 9, недоступны во время компиляции. Их можно сделать доступными во время компиляции с помощью параметра командной строки --add-exports. Во время выполнения они остаются доступными, если были доступны в JDK 8, но в будущем выпуске станут недоступными, и тогда сделать их доступными и во время выполнения можно будет параметрами --add-exports или --add-opens. Параметр --illegal-access управляет доступностью этих API во время выполнения и может использоваться, чтобы имитировать будущую недоступность внутренних API во время выполнения.
Критически важные внутренние API, не инкапсулированные в JDK 9
Здесь перечислены критически важные внутренние API, которые не инкапсулированы в JDK 9, потому что в JDK 8 для них не было поддерживаемых замен.
-
sun.misc.{Signal,SignalHandler} -
sun.misc.Unsafe(Функциональность многих методов этого класса доступна через variable handles (JEP 193).) -
sun.reflect.Reflection::getCallerClass(int)(Функциональность этого метода доступна в API обхода стека, определённом в JEP 259.) -
sun.reflect.ReflectionFactory -
com.sun.nio.file.{ExtendedCopyOption,ExtendedOpenOption, ExtendedWatchEventModifier,SensitivityWatchEventModifier}
Эти API определены и экспортируются специфичным для JDK модулем jdk.unsupported. Этот модуль присутствует в полных образах JRE и JDK. Поэтому эти API по умолчанию доступны коду в class path и доступны коду в модулях, если эти модули объявляют зависимость от модуля jdk.unsupported.
Критически важные внутренние API, для которых в JDK 9 появились замены, в JDK 9 помечены как Deprecated и в будущем выпуске будут либо инкапсулированы, либо удалены.
Поскольку jdk.unsupported экспортирует и открывает пакеты sun.misc и sun.reflect, все некритичные внутренние API в этих пакетах были, в зависимости от ситуации, либо перенесены в другой пакет, либо удалены. Стандартные модули и модули JDK, которые не подлежат обновлению, не должны зависеть от модуля jdk.unsupported, а должны использовать соответствующие внутренние API.
Те, кто сопровождает библиотеки, использующие критически важные внутренние API, для которых в JDK 9 есть замены, могут воспользоваться Multi-Release JAR Files (JEP 238), чтобы поставлять единый артефакт, который в выпусках до JDK 9 использует старые API, а в более поздних выпусках — API-замены.
Риски и допущения
Если какой-либо широко используемый критически важный внутренний API не был признан критически важным и был перенесён или удалён, то приложения, зависящие от него, перестанут работать.
Если какой-либо широко используемый критически важный внутренний API не был признан критически важным, но всё ещё существует, то приложения, зависящие от него, могут вызывать предупреждение в этом выпуске и перестанут работать в будущем выпуске.
Краткосрочное решение в обоих случаях — конечный пользователь открывает доступ к API с помощью упомянутого выше параметра командной строки; в более долгосрочной перспективе, в одном из следующих выпусков, API может быть перенесён в модуль jdk.unsupported и экспортирован для внешнего использования.
Некритичные внутренние API, ранее находившиеся в пакетах sun.misc и sun.reflect, были либо перенесены, либо удалены. Существующий код, который от них зависит, может работать некорректно.
Зависимости
JEP 200 (The Modular JDK) определяет модульную структуру JDK, а JEP 261 (Module System) реализует модульную систему.