Обновете критично Java 8 приложение на етапи: направете списък на всяка зависимост, преминете първо към Java 11, а след това към всяка следваща версия с дългосрочна поддръжка (LTS) и оставете тестовете и тестовете с натоварване да решат кога всяка стъпка е безопасна. По-голямата част от работата е в библиотеките, инструментите за компилиране и кода, който засяга вътрешностите на JDK, а не в бизнес логиката Ви.
Оставането на Java 8 стеснява възможностите Ви всяка година
Едно Java 8 приложение може да продължи да работи с години и точно в това е капанът. Поправките за сигурност все повече зависят от платен договор за поддръжка или от дистрибуция, която все още ги пренася назад, а големите библиотеки са продължили напред. Spring Boot 3 например изисква минимум Java 17, така че оставането на Java 8 замразява и версиите на рамката Ви.
По-новите JVM изпълняват и същия код по-добре. G1 е събирачът на боклук по подразбиране от Java 9, събирачи с кратки паузи като ZGC са готови за продукционна среда, а компактните низове (compact strings) намаляват използваната памет при натоварвания с много текст. Инженерите очакват и модерни възможности на езика като records, text blocks и switch изрази, което прави по-трудно намирането на хора за кодова база на Java 8.
Започнете със списък на всичко, от което зависи приложението
Самото обновяване на JDK рядко е трудната част. Трудното е дългата опашка от библиотеки, плъгини и агенти, писани за Java 8 и никога не обновявани. Съставете пълен списък, преди да промените каквото и да било, и запишете версията на всеки елемент.
- Доставчикът и версията на JDK във всяка среда, от лаптопите на разработчиците до продукционната среда.
- Преките и транзитивните зависимости, експортирани от дървото на зависимостите в Maven или от отчета за зависимостите в Gradle.
- Плъгините за компилиране, генераторите на код и процесорите на анотации като Lombok.
- Сървърът за приложения или сървлет контейнерът, ако приложението работи в такъв.
- Java агентите за наблюдение, профилиране или сигурност, които се закачат дълбоко в JVM.
- Кодът, който използва вътрешни API на JDK, открит с инструмента jdeps и неговата опция jdk-internals.
- Флаговете на JVM, настройките на събирача на боклук и всички скриптове, които разбират изхода на java -version.
Минавайте през версиите с дългосрочна поддръжка, вместо да прескачате
Преминете от Java 8 към 11, след това към 17, а после към 21 или 25. Всяка стъпка има собствен набор от премахнати неща и промени в поведението, а един голям скок смесва всички тях в една грешка, която не можете да диагностицирате. Поправянето на по един слой наведнъж поддържа всяка стъпка достатъчно малка, за да бъде прегледана и върната назад.
Където е възможно, обновявайте библиотеките, докато още сте на Java 8, тъй като много от последните им версии поддържат както стари, така и нови JDK. След това пуснете съществуващата компилация на новата JVM, преди да промените целта на компилацията. Така проблемите при изпълнение се отделят от проблемите на компилатора, а флагът release на компилатора държи целевата версия на байткода изрична.
Направете тестовете условие за всяка стъпка
Тестовете са единственият Ви обективен сигнал, че обновеното приложение се държи по същия начин. Ако критичните пътища са слабо покрити, първо напишете характеризиращи тестове: тестове, които улавят какво прави системата днес, включително странните ѝ гранични случаи, без да преценяват дали това поведение е правилно.
Добавете интеграционни тестове с реална база данни и реални брокери на съобщения, защото много грешки при обновяване се появяват само на тези граници. За системи с много изчисления пуснете едни и същи входни данни през старата и новата версия и сравнете резултатите поле по поле. Обърнете внимание на датите, числата и текста: Java 9 премина по подразбиране към локалните данни на CLDR, а Java 18 направи UTF-8 кодировката по подразбиране, и двете промени могат незабелязано да променят форматирането или разбора.
Познавайте капаните, които чупят кода на Java 8
Повечето повреди попадат в няколко известни категории. Потърсете всяка от тях преди обновяването, вместо да ги откриете в продукционна среда.
- Премахнатите модули на Java EE и CORBA: Java 11 извади от JDK JAXB, JAX-WS, JavaBeans Activation и общите анотации, така че те трябва да се добавят отново като изрични зависимости.
- Строгото капсулиране на вътрешностите на JDK: непозволеният достъп чрез reflection предизвикваше предупреждения от Java 9, отказва се по подразбиране от Java 16 и не може да бъде включен отново глобално от Java 17. Поправете го, като обновите библиотеката; използвайте add-opens само като документирано временно изключение.
- Остарели инструменти за байткод: по-старите версии на Lombok, Mockito, Byte Buddy, ASM и плъгините за компилиране се провалят при по-новите версии на class файловете.
- Премахнати функции: JavaScript енджинът Nashorn беше премахнат в Java 15, а Security Manager беше обявен за остарял в Java 17 и окончателно изключен в Java 24.
- Премахнати флагове на JVM: събирачът на боклук CMS беше премахнат в Java 14, а JVM, стартирана с премахнати опции, може да откаже да се стартира.
Докажете производителността при реалистично натоварване, а не на лаптоп
Новият JDK променя събирача на боклук, JIT компилатора и разположението в паметта, така че производителността може да се промени и в двете посоки. Пуснете тест с натоварване, който възпроизвежда профила на продукционния трафик, на същия хардуер или тип инстанция, преди и след всяка стъпка. Сравнете перцентилите на латентността, пропускателната способност, паметта и паузите за събиране на боклука и оставете JIT да загрее, преди да измервате.
Нашите инженери ръководиха миграция от Java 8 към 16 на критично приложение за дневна търговия с газ за национално бюро за търговия с газ, като работеха чрез Sopra Steria. В тази система изчисленията на капацитета и енергийните потоци трябваше да остават точни и бързи при високочестотно натоварване, затова обновяването вървеше заедно с оптимизация на тези изчисления и беше проверено под натоварване, а не просто прието за успешно.
Внедрявайте постепенно и запазете път за връщане
Пуснете обновената среда за изпълнение първо на една инстанция или за малък дял от трафика и следете процента на грешките, латентността и поведението на събирача на боклук спрямо базовото ниво на Java 8. Поддържайте предишната компилация готова за внедряване, докато новата версия не премине през нормалните бизнес цикли, включително края на месеца или пиковите периоди.
Едва тогава премахнете артефактите на Java 8 и започнете да използвате новите възможности на езика. Ако искате помощ за планирането или изпълнението на подобно обновяване, SDK Enterprises осигурява екип от собствени инженери и проверени специалисти по един договор с ясна отговорност.
Основното накратко
- Усилията при обновяване от Java 8 са главно в зависимостите, инструментите за компилиране и използването на вътрешностите на JDK, а не в бизнес логиката.
- Минавайте през версиите с дългосрочна поддръжка една по една, за да има всяка грешка една-единствена причина, която може да се открие.
- Характеризиращите и интеграционните тестове са условието за всяка стъпка, особено около датите, числата и кодировката на текста.
- Проверете производителността при натоварване, близко до продукционното, защото промените в събирането на боклука и в JIT могат да изместят резултатите и в двете посоки.
- Пуснете първо за малък дял от трафика и поддържайте компилацията на Java 8 готова за внедряване, докато новата среда за изпълнение не се докаже.
Въпроси и отговори
Мога ли да обновя директно от Java 8 към Java 21?
Можете, но наследявате наведнъж всички промени от Java 9 до 21, което прави грешките трудни за проследяване. Минаването през 11 и 17 струва малко повече време за компилиране и спестява много отстраняване на грешки при критична система.
Колко време отнема обновяването от Java 8?
Зависи от броя зависимости, колко от тях използват вътрешностите на JDK, покритието с тестове и колко тестове с натоварване изисква системата. Списъкът на зависимостите и пробното пускане на новата JVM Ви дават реалистична оценка рано, преди да се ангажирате с график.
Трябва ли да пренапиша кода, за да използвам новите възможности на Java?
Не. Java запазва силна обратна съвместимост за код, който се придържа към стандартни API, които не са обявени за остарели. Въвеждайте records, text blocks и другите възможности постепенно, след като обновената среда за изпълнение е стабилна в продукционна среда.