JavaRush /Java курси /Модуль 5. Spring /Інструменти розробника

Інструменти розробника

Модуль 5. Spring
Рівень 15 , Лекція 4
Відкрита

Spring Boot містить додатковий набір інструментальних засобів, які можуть зробити процес розробки додатків трохи приємнішим. Модуль spring-boot-devtools можна додавати до будь-якого проєкту для забезпечення додаткових функцій під час розробки. Щоб впровадити підтримку інструментальних засобів розробки (devtools), додай залежність модуля до свого складання, як показано в наступних лістингах для Maven та Gradle:

Maven
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <optional>true</optional>
    </dependency>
</dependencies>
Gradle
dependencies {
    developmentOnly("org.springframework.boot:spring- boot-devtools")
}
Інструментальні засоби розробки автоматично деактивуються при виконанні повністю упакованої програми. Якщо твоя програма запускається через java-jar або через спеціальний завантажувач класів, вона вважається "виробничим додатком". Ти можеш керувати цією логікою роботи за допомогою системної властивості spring.devtools.restart.enabled. Щоб активувати devtools, незалежно від завантажувача класів, який використовується для запуску програми, встанови системну властивість -Dspring.devtools.restart.enabled=true. Цього не можна робити у виробничому середовищі, де виконання devtools становить загрозу безпеці. Щоб відключити devtools, вимкни залежність або встанови системну властивість -Dspring.devtools.restart.enabled=false.
Якщо позначити залежність у Maven як необов'язкову або використовувати конфігурацію developmentOnly у Gradle (як показано вище), це запобігатиме транзитному застосуванню devtools до інших модулів, що використовують твій проєкт.
Перепаковані архіви за замовчуванням не містять devtools. Якщо ти хочеш використовувати певну функцію віддаленого використання devtools, необхідно включити її до складу. У разі використання плагіна для Maven встанови для властивості excludeDevtools значення false. При використанні плагіна для Gradle конфігуруй classpath для завдання так, щоб він містив конфігурацію developmentOnly.

Діагностика проблем із завантаженням класів

Функціональність перезапуску реалізована за допомогою двох завантажувачів класів. Для більшості програм такий підхід працює добре. Однак іноді він може призвести до проблем із завантаженням класів, особливо в багатомодульних проєктах.

Щоб діагностувати, чи справді проблеми із завантаженням класів викликані devtools та їх двома завантажувачами класів, спробуй вимкнути перезапуск. Якщо це вирішить проблеми, налаштуй перезапуск завантажувача класів на охоплення всього проєкту.

Властивості за замовчуванням

Деякі бібліотеки, що підтримуються Spring Boot, використовують кеші для підвищення продуктивності. Наприклад, шаблонізатори кешують скомпільовані шаблони, щоб уникнути повторного парсингу файлів шаблонів. До того ж, Spring MVC може додавати заголовки HTTP-кешування у відповіді при обробці статичних ресурсів. Хоча кешування дуже корисне у виробничому середовищі, воно може бути контрпродуктивним під час розробки, не дозволяючи бачити зміни, які були тільки що внесені до додатку. Тому spring-boot-devtools за замовчуванням деактивує налаштування кешування.

Налаштування кешу зазвичай конфігуруються за допомогою параметрів у файлі application.properties. Наприклад, Thymeleaf передбачає властивість spring.thymeleaf.cache. Замість того, щоб встановлювати ці властивості вручну, модуль spring-boot-devtools автоматично застосовує адекватну конфігурацію на час розробки.

У наступній таблиці перераховані всі властивості:

Ім'я Значення за замовчуванням

server.error.include-binding-errors

always

server.error.include-message

always

server.error.include-stacktrace

always

server.servlet.jsp.init-parameters.development

true

server.servlet.session.persistent

true

spring.freemarker.cache

false

spring.graphql.graphiql.enabled

true

spring.groovy.template.cache

false

spring.h2.console.enabled

true

spring.mustache.servlet.cache

false

spring.mvc.log-resolved-exception

true

spring.reactor.debug

true

spring.template.provider.cache

false

spring.thymeleaf.cache

false

spring.web.resources.cache.period

0

spring.web.resources.chain.cache

false

Якщо тобі не потрібно, щоб застосовувалися параметри за замовчуванням, то можеш встановити spring.devtools.add-properties у false у файлі application.properties.

Оскільки при розробці додатків на Spring MVC і Spring WebFlux потрібно більше інформації про вебзапити, інструментальні засоби розробки передбачають активацію DEBUG журналювання для web-групи журналювання. Це дасть інформацію про вхідний запит, який обробник його обробляє, про результат відповіді та інші подробиці. Якщо потрібно реєструвати всі відомості запиту (включно з потенційною конфіденційною інформацією), можна включити властивості конфігурації spring.mvc.log-request-details або spring.codec.log-request-details.

Автоматичний перезапуск

Програми, що використовують spring-boot-devtools, автоматично перезапускаються при зміні файлів у classpath. Це може бути корисною функцією при роботі в IDE, оскільки забезпечує дуже швидкий зворотний зв'язок для внесення змін до коду. За замовчуванням будь-який запис у classpath, що вказує на каталог, відстежується щодо змін. Зверни увагу, що деякі ресурси, такі як статичний вміст та шаблони подання, не вимагають перезапуску програми.

Ініціація перезапуску

Оскільки DevTools відстежує ресурси в classpath, єдиним способом ініціювати перезапуск є оновлення classpath. Незалежно від того, чи використовуєте ви IDE або один із плагінів складання, змінені файли потрібно перекомпілювати, щоб ініціювати перезапуск. Спосіб оновлення classpath залежить від використовуваного інструменту:

  • В Eclipse збереження зміненого файлу призводить до оновлення classpath та ініціює перезапуск.

  • У IntelliJ IDEA складання проекту (Build +→+ Build Project) має той самий ефект.

  • Якщо використовується плагін складання, виконання mvn compile для Maven або gradle build для Gradle призведе до ініціації перезапуску.

Якщо перезапуск здійснюється за допомогою Maven або Gradle з використанням плагіна складання, то потрібно залишити значення forking, встановлене в enabled. Якщо ти відключиш розгалуження (форкінг), ізольований завантажувач класів програми, що використовується devtools, не буде створено, а перезавантаження не буде працювати належним чином.
показує себе дуже добре під час використання з LiveReload. Якщо ти використовуєш JRebel, автоматичне перезавантаження вимкнено на користь динамічного перезавантаження класів. Інші функції devtools (такі як LiveReload і перевизначення властивостей), як і раніше, можна буде використовувати. DevTools використовують перехоплювач завершення контексту додатку, щоб закрити його під час перезапуску. Робота не буде коректною, якщо перехоплювач завершення вимкнений (SpringApplication.setRegisterShutdownHook(false)).
DevTools необхідно налаштувати завантажувач ResourceLoader, який використовується ApplicationContext. Якщо твій додаток вже передбачає такий завантажувач, він буде обернутий. Пряме перевизначення методу getResource на ApplicationContext не підтримується.
Автоматичний перезапуск не підтримується під час використання прив'язки за допомогою AspectJ.

Перезапуск та перезавантаження

Технологія перезапуску, передбачена Spring Boot, працює за допомогою двох завантажувачів класів. Класи, які не змінюються (наприклад, класи зі сторонніх jar-файлів), завантажуються до основного завантажувача класів. Класи, які активно розробляються, завантажуються до завантажувача класів, що перезапускає. Якщо програма перезапускається, перезапускаючий завантажувач класів одночасно використовується, після чого створюється новий. Такий підхід означає, що перезапуск програми зазвичай відбувається набагато швидше, ніж "холодний запуск", оскільки основний завантажувач класів вже доступний і заповнений.

Якщо ти виявиш, що перезавантаження недостатньо швидке для твоїх програм або ти стикаєшся з проблемами завантаження класів, можна ознайомитися з технологіями перезавантаження, такими як JRebel від ZeroTurnaround. Вони працюють шляхом переписування класів у міру їх завантаження, щоб вони були зручнішими для повторного завантаження. За замовчуванням при кожному перезапуску програми до журналу заноситься звіт, що показує дельту обчислення стану. Звіт демонструє зміни в автоконфігурації вашої програми в міру того, як ти вносиш зміни, такі як додавання або видалення бінів і встановлення властивостей конфігурації. Щоб вимкнути журналювання з формуванням звіту, встанови таку властивість:

Properties
spring.devtools.restart.log-condition-evaluation-delta=false
Yaml
spring: devtools: restart: log-condition-evaluation-delta: false

Вилучення ресурсів

Деякі ресурси не обов'язково повинні ініціювати перезавантаження при їх зміні. Наприклад, шаблони Thymeleaf можна редагувати на тому ж місці. За замовчуванням зміна ресурсів у /META-INF/maven, /META-INF/resources, /resources, /static, /public або /templates не ініціює перезапуск, але ініціює перезавантаження в реальному часі. Якщо ти бажаєш налаштувати ці винятки, можна використовувати властивість spring.devtools.restart.exclude. Наприклад, щоб вимкнути лише /static та /public, потрібно встановити таку властивість:

Properties
spring.devtools.restart.exclude=static/**,public/**
Yaml
spring: devtools: restart: exclude: "static/**,public/**"
Якщо ти хочеш зберегти ці значення за замовчуванням і додати додаткові винятки, використовуй властивість spring.devtools.restart.additional-exclude .

Відстеження додаткових шляхів

Тобі може знадобитися, щоб програма перезапускалася або перезавантажувалася після внесення змін до файлів, яких немає в classpath. Для цього використовуй властивість spring.devtools.restart.additional-paths, щоб налаштувати додаткові шляхи для відстеження змін. Ти можеш використовувати властивість spring.devtools.restart.exclude, щоб керувати тим, чи будуть зміни в додаткових шляхах ініціювати повний перезапуск або перезавантаження в реальному часі.

Вимкнення перезапуску

Якщо тобі не потрібно використовувати функцію перезапуску, можна вимкнути її за допомогою властивості spring.devtools.restart.enabled. У більшості випадків можна встановити цю властивість у файлі application.properties (так все одно ініціалізуватиметься перезапускаючий завантажувач класів, але зміни файлів не будуть відстежуватися).

Якщо потрібно повністю вимкнути засоби підтримки перезапуску (наприклад, через те, що вони не працюють з певною бібліотекою), то перед викликом SpringApplication.run(…) потрібно встановити властивість System для spring.devtools.restart.enabled у false, як це показано в наступному прикладі:

Java

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class MyApplication {
    public static void main(String[] args) {
        System.setProperty("spring.devtools.restart.enabled", "false");
        SpringApplication.run(MyApplication.class, args);
    }
}
Kotlin

import org.springframework.boot.SpringApplication
import org.springframework.boot.autoconfigure.SpringBootApplication
@SpringBootApplication
object MyApplication {
    @JvmStatic
    fun main(args: Array<String>) {
        System.setProperty("spring.devtools.restart.enabled", "false")
        SpringApplication.run(MyApplication::class.java, *args)
    }
}

Використання тригерного файлу

Якщо ти працюєш з IDE, яка постійно компілює файли, що змінюються, то можна віддати перевагу ініціації перезавантаження тільки в певні моменти. Для цього ти можеш використовувати "тригерний файл", що є спеціалізованим файлом, який необхідно змінити, якщо ти дійсно хочеш ініціювати перевірку перезапуску.

Будь-яке оновлення файлу викликає перевірку, але перезапуск відбувається тільки в тому випадку, якщо Devtools виявляють, що їм потрібно щось робити в ім'я (виключаючи шлях) твого тригерного файлу. Тригерний файл повинен знаходитися десь у вашому classpath.

Наприклад, якщо у тебе є проєкт із наступною структурою:

src
+- main
    +- resources
        +- .reloadtrigger
            

Тоді властивість вашого trigger-file буде таким:

Properties
spring.devtools.restart.trigger-file=.reloadtrigger
Yaml
spring:
    devtools:
        restart:
            trigger-file: ".reloadtrigger "

Перезапуск буде відбуватися тільки під час оновлення src/main/resources/.reloadtrigger.

Можливо, тобі захочеться встановити spring.devtools.restart.trigger-file як глобальний параметр, щоб усі твої проєкти мали однакову логіку роботи.

У деяких IDE існують функції, які позбавляють необхідності оновлювати тригерний файл вручну. Spring Tools для Eclipse та IntelliJ IDEA (Ultimate Edition) мають такі засоби отримання. У Spring Tools ти можеш використовувати кнопку "reload" з подання консолі (за умови, що твій trigger-file має ім'я .reloadtrigger). У випадку з IntelliJ IDEA можна дотримуватися інструкцій у відповідній документації..

Налаштування завантажувача класів, що перезапускає

Функціональність перезапуску реалізована через два завантажувача класів. Якщо виникають якісь проблеми, тобі може знадобитися налаштувати, що і яким завантажувачем класів завантажуватиметься.

За замовчуванням будь-який відкритий проєкт в IDE завантажується із завантажувачем класів, що перезапускає, а будь-який звичайний .jar-файл завантажується з "основним" завантажувачем класів. Те ж саме, якщо використовується mvn spring-boot:run або gradle bootRun: проєкт, що містить анотацію @SpringBootApplication, завантажується з "перезапускаючим" завантажувачем класу, а все інше — з "основним" завантажувачем класів.

Можна дати Spring Boot команду завантажувати компоненти проєкту з іншим завантажувачем класів, створивши файл META-INF/spring-devtools.properties. Файл spring-devtools.properties може містити властивості з префіксами restart.exclude та restart.include. Елементи include — це компоненти, які потрібно підняти вгору в "завантажувач класів, що перезапускає", а елементи exclude — це елементи, які потрібно опустити вниз в "основний" завантажувач класів. Значення властивості є шаблоном регулярних виразів, який застосовується до classpath, як показано в наступному прикладі:

Properties
restart.exclude.companycommonlibs=/mycorp-common-[\\w\\d-\\.]+\\.jar
restart.include.projectcommon=/mycorp-myproj-[\\w\\d-\\.]+\ \.jar
Yaml
restart:
    exclude:
        companycommonlibs: "/mycorp-common-[\\w\\d-\\.]+\\.jar"
    include:
        projectcommon: "/mycorp-myproj-[\\w\\d-\\.]+\\.jar "
Усі ключі властивостей повинні бути унікальними. Якщо властивість починається з restart.include. або restart.exclude., вона враховується.
Завантажуються всі META-INF/spring-devtools.properties з classpath. Ти можеш упаковувати файли всередині свого проєкту або в бібліотеках, які використовує проєкт.

Відомі обмеження

Функціональність перезапуску не дуже добре працює з об'єктами, які десеріалізуються за допомогою стандартного ObjectInputStream. Якщо необхідно десеріалізувати дані, то може знадобитися використовувати ConfigurableObjectInputStream зі Spring у поєднанні з Thread.currentThread().getContextClassLoader().

На жаль, деякі сторонні бібліотеки десеріалізують без урахування контекстного завантажувача класів. Якщо ти зіткнешся з такою проблемою, необхідно буде зробити запит на виправлення до авторів-творців.

LiveReload

Модуль spring-boot-devtools містить вбудований сервер LiveReload, який можна використовувати для ініціації оновлення браузера під час зміни ресурсу. Розширення для браузера LiveReload для Chrome, Firefox та Safari знаходяться у вільному доступі на сайті livereload.com.

Якщо запускати сервер LiveReload під час виконання програми не потрібно, то можна встановити властивість spring.devtools.livereload.enabled у false.

Одночасно можна запустити лише один сервер LiveReload. Перед запуском програми переконайся, що інші сервери LiveReload не запущені. Якщо ти запускаєш кілька програм з IDE, тільки перша з них підтримуватиме LiveReload.
Для ініціації функції LiveReload при зміні файлу, автоматичний перезапуск повинен бути увімкнений.

Глобальні параметри

Ти можеш налаштувати глобальні параметри devtools, додавши будь-який з наступних файлів до каталогу $HOME/.config/spring-boot:

  1. spring-boot-devtools.properties

  2. spring-boot-devtools.yaml

  3. spring-boot-devtools.yml

Будь-які властивості, додані в ці файли застосовуються до усіх програм Spring Boot у твоїй машині, які використовують devtools. Наприклад, щоб налаштувати перезапуск на постійне використання тригерного файлу, потрібно додати таку властивість до файлу spring-boot-devtools:

Properties
spring.devtools.restart.trigger-file=.reloadtrigger
Yaml
spring:
    devtools:
        restart:
            trigger-file: ".reloadtrigger"

За замовчуванням $HOME — це початковий каталог користувача. Щоб налаштувати це місце, встанови змінну оточення SPRING_DEVTOOLS_HOME або системну властивість spring.devtools.home.

Якщо конфігураційні файли devtools не будуть знайдені в $HOME/.config/spring-boot, в корені каталогу $HOME буде здійснено пошук на предмет наявності файлу . spring-boot-devtools.properties. Це дозволить спільно використовувати глобальну конфігурацію devtools з додатками, які працюють на більш старій версії Spring Boot, яка не підтримує розташування $HOME/.config/spring-boot.

Профілі не підтримуються у файлах properties/yaml для devtools.

Будь-які профілі активовані в .spring-boot-devtools.properties, не впливатимуть на завантаження пов'язаних із конкретним профілем файлів. Імена файлів, специфічні для профілів (виду spring-boot-devtools-<profile>.properties), та документи spring.config.activate.on-profile у файлах YAML і Properties не підтримуються.

Конфігурування watcher-а файлової системи

FileSystemWatcher працює шляхом опитування змін класу в певних інтервалах часу, а потім чекає на певний період бездіяльності, щоб переконатися, що змін більше немає. Оскільки Spring Boot повністю покладається на IDE при компіляції та копіюванні файлів у місце, звідки Spring Boot може їх прочитати, ти можеш зіткнутися з тим, що деякі зміни не будуть відображені при перезапуску програми за допомогою devtools. Якщо вти спостерігаєш подібні проблеми постійно, спробуйте збільшити параметри spring.devtools.restart.poll-interval та spring.devtools.restart.quiet-period до значень, які відповідають твоєму оточенню розробки:

Properties
spring.devtools.restart.poll-interval=2s
spring.devtools.restart.quiet-period= 1s
Yaml
spring:
    devtools:
        restart:
            poll-interval : "2s"
            quiet-period: "1s"

Тепер відстежувані каталоги classpath опитуються кожні 2 секунди на предмет змін, а 1-секундний період бездіяльності дотримується, щоб переконатися у відсутності додаткових змін класів.

Віддалені програми

Інструменти розробника Spring Boot не обмежуються локальною розробкою. Ти також можеш використовувати кілька функцій під час віддаленого запуску програм. Засоби підтримки дистанційної роботи приймаються за бажанням, оскільки їх активація може становити загрозу безпеці. Їх слід активувати лише при роботі в довіреній мережі або за наявності захисту за допомогою SSL. Якщо жоден з цих варіантів недоступний, не слід використовувати засоби підтримки дистанційної роботи для DevTools. У жодному разі не слід активувати засоби підтримки при виробничому розгортанні.

Щоб активувати підтримку, необхідно переконатися, що devtools міститься в переупакованому архіві, як показано в наступному лістингу:

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <configuration>
                <excludeDevtools>false</excludeDevtools>
            </configuration>
        </plugin>
    </plugins>
</build>

Тому необхідно встановити властивість spring.devtools.remote.secret. Як і будь-який важливий пароль або конфіденційні відомості, значення має бути унікальним і надійним, щоб його не можна було вгадати або підібрати методом перебору.

Засоби підтримки віддаленої роботи для devtools надаються в двох частинах: кінцева точка на стороні сервера, приймаюча з'єднання, і клієнтська програма, яку ти виконуєш у своїй IDE. Серверний компонент автоматично активується, якщо встановлено властивість spring.devtools.remote.secret. Клієнтський компонент потрібно запускати вручну.

Віддалена робота з devtools не підтримується для програм Spring WebFlux.

Виконання віддаленої клієнтської програми

Віддалена клієнтська програма розроблена для виконання з твоєї IDE. Необхідно виконати org.springframework.boot.devtools.RemoteSpringApplication з тим же classpath, що й віддалений проєкт, до якого ти підключаєшся. Єдиним обов'язковим аргументом програми є віддалена URL-адреса, до якої вона підключається.

Наприклад, якщо використовується Eclipse або Spring Tools і є проєкт з ім'ям my-app, який розгорнути в Cloud Foundry, потрібно зробити таке:

  • Вибрати Run Configurations… з меню Run.

  • Створити нову "конфігурацію запуску" Java Application.

  • Знайти проєкт my-app.

  • Використовувати org.springframework.boot.devtools.RemoteSpringApplication як основний клас.

  • Додати https://myapp.cfapps.io у Program arguments (або будь-яка інша URL-адреса вашого віддаленого доступу).

Віддалений клієнт, що виконується, може виглядати так:

 .   ____          _                                              __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _          ___               _      \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` |        | _ \___ _ __  ___| |_ ___ \ \ \ \
 \\/  ___)| |_)| | | | | || (_| []::::::[]   / -_) '  \/ _ \  _/ -_) ) ) ) )
  '  |____| .__|_| |_|_| |_\__, |        |_|_\___|_|_|_\___/\__\___|/ / / /
 =========|_|==============|___/===================================/_/_/_/
 :: Spring Boot Remote ::  (v2.7.5)
2022-10-20 12:40:15.175  INFO 16215 --- [           main] o.s.b.devtools.RemoteSpringApplication   : Starting RemoteSpringApplication v2.7.5 using Java 1.8.0_345 on myhost with PID 16215 (/Users/myuser/.m2/repository/org/springframework/boot/spring-boot-devtools/2.7.5/spring-boot-devtools-2.7.5.jar started by myuser in /opt/apps/)
2022-10-20 12:40:15.182  INFO 16215 --- [           main] o.s.b.devtools.RemoteSpringApplication   : Немає активного set, falling back to 1 default profile: "default"
2022-10-20 12:40:15.913  INFO 16215 --- [           main] o.s.b.d.a.OptionalLiveReloadServer       : LiveReload server є керування на port 35729
2022-10-20 12:40:15.946  INFO 16215 --- [           main] o.s.b.devtools.RemoteSpringApplication   : Started RemoteSpring2
Оскільки віддалений клієнт використовує той же classpath, що і фактична програма, він може безпосередньо читати властивості програми. Так зчитується властивість spring.devtools.remote.secret і передається серверу для аутентифікації.
Завжди рекомендується використовувати https :// в якості протоколу підключення, щоб трафік був зашифрований і паролі не можна було перехопити. Якщо необхідно використати проксі для доступу до віддаленого застосунку, налаштуй властивості spring.devtools.remote.proxy.host та spring.devtools.remote.proxy.port.

Видалене оновлення

Віддалений клієнт відстежує зміни в шляху класів твоєї програми так само, як це робить програма локального перезапуску. Будь-який оновлений ресурс передається віддаленому додатку і (якщо потрібно) ініціює перезапуск. Це може бути корисним, якщо ти повторюєш функцію, яка використовує хмарну службу, якої немає на локальному рівні. Зазвичай віддалене оновлення та перезавантаження відбуваються набагато швидше, ніж повна перебудова та розгортання.

В оточенні з повільною розробкою може статися так, що періоду бездіяльності буде недостатньо, а зміни в класах можуть бути розбиті на пакети. Сервер перезапускатиметься після завантаження першого пакета змін класу. Наступний пакет не можна буде відправити до програми, оскільки сервер перезапускається.

Зазвичай це проявляється у вигляді попередження в журналах RemoteSpringApplication про те, що не вдалося завантажити деякі класи, і подальшої повторної спроби. Але це також може вилитися в неузгодженість коду програми та неможливість перезапуску після завантаження першого пакета змін. Якщо ти спостерігаєш подібні проблеми постійно, спробуй збільшити параметри spring.devtools.restart.poll-interval та spring.devtools.restart.quiet-period до значень, які відповідають вашому оточенню розробки.

Файли відстежуються лише під час виконання віддаленого клієнта.Якщо ти зміниш файл до запуску віддаленого клієнта, він не буде перенесений на віддалений сервер.
Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ