Solar InRights: отрицание, гнев, депрессия, торг, переход на Java 16

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

Привет! Большинство разработчиков не спешат обновляться до новых версий Java. Многие опасаются, что все сломается, что появятся скрытые баги, что это займет очень много времени. Сегодня мы поделимся опытом перевода IGA-системы Solar InRights с Java 8 на актуальную Java 16, расскажем, для чего мы это сделали и почему именно сейчас. Подробно опишем, какие проблемы могут возникнуть при обновлении и как их устранить, а главное – поделимся тем, что мы в итоге получили.

Ранее в разработке мы использовали Java 8. Эта версия платформы и сейчас является достаточно стабильной и функциональной, в целом это понятная и удобная версия.

Однако в экосистеме произошло несколько важных событий, которые подтолкнули нас к переходу:

  • Была выпущена Java 9 со значительными архитектурными изменениями. Начиная с этой версии платформа Java является модульной, появляются разные выпуски JVM с различным набором фич. Эти изменения ломают обратную совместимость, и большинство программ, написанных на Java 8, не запускаются на Java 9+.

  • С выпуском Java 11 компания Oracle представила новую модель лицензирования и подписки. Теперь нужно особенно внимательно следить за тем, какую версию и где мы используем, чтобы не нарушить лицензию.

  • Релиз Java 16 включает множество новых возможностей в языке Java. Да, кто-то обязательно возразит, что аргумент слабый. Можно и дальше пользоваться Java 8, где все понятно, просто и удобно. Но с новыми синтаксическими конструкциями Java 16 писать код удобнее, а отслеживать ошибки проще. Наряду с уже перечисленными причинами это довольно приятный бонус.

У нас появилось свободное время на развитие системы, поэтому мы решили перейти на актуальный выпуск Java, и чем раньше это произойдет, тем легче будет процесс перехода. Версии с 11 по 16 называются промежуточными, потому что у них короткий период поддержки – 6 месяцев. На сентябрь 2021 года запланирован LTS (Long Term Support) релиз Java 17.

Так мы решили перейти на Java 16, чтобы затем быстро перейти на LTS Java 17.

С чем имеем дело

Система Solar inRights в собранном виде – это веб-приложение в виде war-файла, которое запускается на сервере Tomcat. Для сборки используем Maven. Код организован по функциональным модулям. Один модуль – это один maven-проект.

Система состоит из нескольких слоев:

Мы активно используем Spring для инверсии зависимостей, Hibernate для абстракции над логикой баз данных и JAXB для сериализации данных. Для написания тестов используем язык Groovy, а запускаем тесты с помощью TestNG.

В результате получается модульный монолит, в classpath которого собраны ресурсы от всех зависимостей.

Обновление на Java 16

На текущий момент новейшая стабильная версия JDK – это 16. Это preview release, значит некоторые языковые конструкции могут быть изменены или отсутствовать в следующей версии Java.

Мы решили, что будем собирать систему с помощью Liberica JDK 16 с русскоязычной поддержкой, но нам подойдет и OpenJDK, и любая открытая сборка JDK без специальных особенностей.

Просто взять и собрать систему на JDK 16 не получилось. Видим море ошибок, говорящих о том, что наш код обращается к закрытым частям платформы. Теперь нельзя обращаться к com.sun.*, java.security.* и прочим внутренностям JDK.

Изменяем работу с XML на использование открытых API.

Было:

import
com.sun.org.apache.xerces.internal.jaxp.datatype.XMLGregorianCalendarImpl;
import com.sun.org.apache.xml.internal.utils.XMLChar;
import com.sun.org.apache.xerces.internal.dom.DeferredElementNSImpl;

Стало:

import javax.xml.datatype.XMLGregorianCalendar;
import org.apache.xerces.util.XMLChar;
import org.w3c.dom.Node;

При сборке Maven отказывается читать наши Mojo, потому что не знает, как читать байткод классов, скомпилированных в Java 16. Обновляем версии зависимостей maven-plugin-tools (на текущий момент это 3.6.1):

<dependency>
		<groupId>org.apache.maven.plugin-tools</groupId>
		<artifactId>maven-plugin-tools-generators</artifactId>
		<version>3.6.1</version>
</dependency>
<dependency>
		<groupId>org.apache.maven.plugin-tools</groupId>
		<artifactId>maven-plugin-tools-api</artifactId>
		<version>3.6.1</version>
</dependency>
<dependency>
		<groupId>org.apache.maven.plugin-tools</groupId>
		<artifactId>maven-plugin-tools-annotations</artifactId>
		<version>3.6.1</version>
</dependency>
<dependency>
		<groupId>org.apache.maven.plugin-tools</groupId>
		<artifactId>maven-plugin-annotations</artifactId>
		<version>3.6.1</version>
</dependency>
<dependency>
		<groupId>org.apache.maven.plugin-tools</groupId>
		<artifactId>maven-plugin-tools-java</artifactId>
		<version>3.6.1</version>
</dependency>

У Maven также будут проблемы с чтением конфигурации из javadoc. Исправляем формат javadoc в Mojo классах.

Было:

/** @parameter default-value="${project}" */
private MavenProject project;

Стало:

/**
* @parameter default-value="${project}"
*/
private MavenProject project;

Обновляем версию плагина Maven для запуска TestNG:

<dependency>
		<groupId>org.apache.maven.surefire</groupId>
		<artifactId>surefire-testng</artifactId>
    <version>2.22.23.0.0-M5</version>
</dependency>

Теперь нужно обновить библиотеки проксирования и манипуляций с байткодом – все, что изменяет внутреннюю структуру классов. У нас получилось так:

<dependency>
		<groupId>org.ow2.asm</groupId>
		<artifactId>asm</artifactId>
		<version>9.1</version>
</dependency>
<dependency>
		<groupId>org.apache.bcel</groupId>
		<artifactId>bcel</artifactId>
		<version>6.5.0</version>
</dependency>
<dependency>
		<groupId>org.codehaus.plexus</groupId>
		<artifactId>plexus-classworlds</artifactId>
		<version>2.6.0</version>
</dependency>

Поскольку Java 16 является preview версией, необходимо добавить параметр сборки --enable- preview. Для Maven можно создать файл .mvn/jvm.config со следующим содержанием:

--enable-preview

Это удобно, потому что опция записана в одном месте, и ее можно удалить, когда мы перейдем на LTS выпуск Java 17.

Запуск тестов показал, что внутри нам требуется доступ к инкапсулированным модулям платформы:

java.lang.IllegalAccessError: class ... (in unnamed module @0x568bf312)
cannot access class ... (in module java.base) because module 
java.base does not export sun.security.util to unnamed module @0x568bf312

В несколько итераций получаем подходящий список параметров запуска:

--enable-preview
--add-opens java.base/java.lang=ALL-UNNAMED
--add-opens java.base/java.util=ALL-UNNAMED
--add-opens java.base/java.util.regex=ALL-UNNAMED
--add-opens java.base/java.io=ALL-UNNAMED
--add-opens java.base/java.util.concurrent=ALL-UNNAMED
--add-opens java.base/java.net=ALL-UNNAMED
--add-opens java.base/java.text=ALL-UNNAMED
--add-opens java.base/java.util.stream=ALL-UNNAMED
--add-opens java.base/java.lang.reflect=ALL-UNNAMED
--add-opens java.xml/javax.xml.datatype=ALL-UNNAMED
--add-opens java.xml/javax.xml.namespace=ALL-UNNAMED
--add-opens java.xml/com.sun.org.apache.xerces.internal.jaxp.datatype=ALL- UNNAMED
--add-exports java.management/sun.management=ALL-UNNAMED
--add-exports java.xml/com.sun.org.apache.xerces.internal.jaxp.datatype=ALL- UNNAMED

Последний шаг – обновить сервер приложений Tomcat. Сейчас новейшей версия – 10, и в ней разработчики требуют, чтобы мы переписали все использования javax.* на jakarta.* – однако нам подойдет Tomcat 9, его последние сборки тоже поддерживают Java 16.

Наконец, система полностью собрана на Java 16 и может быть запущена на любом JDK. Мы используем Liberica JDK и OpenJDK.

При тестировании мы увидели небольшие различия в поведении системы по сравнению с Java 8:

  • Форматирование XMLGregorianCalendar теперь использует формат, настроенный в системе по умолчанию, вместо единого заданного формата. Если мы хотим сохранить прежний формат, мы должны явно его указать.

  • Теперь не допускается хранение в resources файлов, имеющих кириллические символы в названии.

  • JVM теперь не завершит работу, пока все потоки программы не завершат выполнение. Это хороший повод разобраться с ThreadPool, потому что Tomcat не завершит работу до тех пор, пока они не будут закрыты.

Что дальше

В целом обновление прошло быстро, гладко, без сюрпризов. Что мы получили результате:

  • Больше не опасаемся лицензионных ограничений, связанных с Java 8.

  • Чуть более безопасную и производительную платформу с закрытыми уязвимостями, исправленными проблемами быстродействия, новыми фичами.

  • Новые синтаксические конструкции в языке Java, которые уже давно есть в Kotlin и Groovy (например, улучшенный instanceof, record-классы, текстовые блоки).

  • Возможность обновить сторонние зависимости, фреймворки, инструменты.

Java 16 является промежуточным обновлением платформы с коротким циклом поддержки. Мы ожидаем стабильного релиза Java 17 в сентябре, чтобы сразу перевести Solar InRights на LTS выпуск платформы. А это в свою очередь, вместе с обновлением фреймворков и других библиотек, повысит качество продукта в целом.

Автор: Олег Гетманский, архитектор информационных систем "Ростелеком-Солар"

Источник: https://habr.com/ru/company/solarsecurity/blog/572084/


Интересные статьи

Интересные статьи

Фабричный метод - это творческий шаблон проектирования, который предоставляет интерфейс для создания объектов в родительском классе,  но позволяет подклассам изменять тип создаваемых объектов....
Доброго времени суток, друзья! Сегодня я хочу поговорить с вами о трех предложениях, относящихся к JavaScript-классам, которые находятся на 3 стадии рассмотрения: определение ...
Такую точку зрения высказал представитель интернет-регистратора RIPE NCC Марко Хохевонинг (Marco Hogewoning). Однако некоторые члены ИТ-сообщества посчитали такой прогноз излишне опти...
Сегодня (3 мая) президент Eclipse Foundation Майк Милинкович (Mike Milinkovic) написал в своем блоге об окончательных результатах закрытых переговоров между Oracle и Eclipse Foundation о товарн...
Довольно часто владельцы сайтов просят поставить на свои проекты индикаторы курсов валют и их динамику. Можно воспользоваться готовыми информерами, но они не всегда позволяют должным образом настроить...