5.03. Справочник по конфигурациям в Java
Справочник по конфигурациям в Java
1. JVM-аргументы запуска (java [options] …)
Все JVM-аргументы подразделяются на три группы:
-D<property>=<value>— установка системных свойств;-X— нестандартные опции (non-standard), могут отличаться между реализациями JVM;-XX— экспериментальные и внутренние опции управления поведением JVM.
1.1. Системные свойства (-D)
Свойства, устанавливаемые при старте JVM через -Dkey=value, становятся доступны через System.getProperty("key"). Некоторые из них влияют на поведение стандартных библиотек или JVM.
| Свойство | Описание | Возможные значения | Пример |
|---|---|---|---|
java.version | Версия Java Runtime Environment (только для чтения) | Строка, например 17.0.12 | — |
java.home | Путь к установке JRE | Абсолютный путь | /usr/lib/jvm/java-17-openjdk |
java.class.path | Путь кисходным классам и JAR-файлам | Список путей, разделённых : (Unix) или ; (Windows) | -cp lib/*:app.jar |
java.library.path | Поиск нативных библиотек (.so, .dll, .dylib) при вызове System.loadLibrary | Список путей | -Djava.library.path=/opt/native |
java.io.tmpdir | Каталог временных файлов | Путь к директории | /tmp, C:\Temp |
file.encoding | Кодировка по умолчанию для операций ввода-вывода | UTF-8, ISO-8859-1, Windows-1251 и др. | -Dfile.encoding=UTF-8 |
sun.stdout.encoding, sun.stderr.encoding | Кодировка потоков System.out и System.err | Та же, что file.encoding, но можно задать отдельно | -Dsun.stdout.encoding=UTF-8 |
user.language, user.country, user.variant | Локаль по умолчанию | en, ru; US, RU; POSIX, WIN | -Duser.language=ru -Duser.country=RU |
user.timezone | Часовой пояс по умолчанию | UTC, Europe/Moscow, Asia/Yekaterinburg | -Duser.timezone=Europe/Moscow |
http.proxyHost, http.proxyPort, https.proxyHost, https.proxyPort | Настройка HTTP/HTTPS-прокси | Хост и порт | -Dhttp.proxyHost=proxy.local -Dhttp.proxyPort=3128 |
http.nonProxyHosts | Хосты, к которым прокси не применяется | Список имён, разделённых ` | , возможны *и?` |
socksProxyHost, socksProxyPort | SOCKS-прокси | Хост и порт | -DsocksProxyHost=127.0.0.1 -DsocksProxyPort=1080 |
java.net.preferIPv4Stack | Использовать IPv4-стек при наличии дуального стека | true, false | -Djava.net.preferIPv4Stack=true |
java.net.preferIPv6Addresses | Предпочитать IPv6-адреса при разрешении имён | true, false | -Djava.net.preferIPv6Addresses=true |
networkaddress.cache.ttl | TTL кэша DNS-имён (в секундах), положительное число | 0 (никогда не кэшировать), -1 (кэшировать навсегда), 30, 60, и т.д. | -Dnetworkaddress.cache.ttl=30 |
networkaddress.cache.negative.ttl | TTL для отрицательных DNS-ответов | то же | -Dnetworkaddress.cache.negative.ttl=10 |
jdk.tls.client.protocols, jdk.tls.server.protocols | Разрешённые TLS-протоколы | TLSv1.2, TLSv1.3, TLSv1,TLSv1.1,TLSv1.2 | -Djdk.tls.client.protocols=TLSv1.2,TLSv1.3 |
jdk.tls.disabledAlgorithms | Алгоритмы, запрещённые для TLS | Список, как в java.security (см. ниже) | -Djdk.tls.disabledAlgorithms=SSLv3, RC4, MD5 |
javax.net.ssl.trustStore, javax.net.ssl.trustStorePassword, javax.net.ssl.keyStore, javax.net.ssl.keyStorePassword | Пути и пароли к хранилищам сертификатов | Путь к файлу JKS/PKCS12, пароль | -Djavax.net.ssl.trustStore=trust.jks -Djavax.net.ssl.trustStorePassword=changeit |
jdk.serialFilter | Глобальный фильтр десериализации (Java ≥ 9) | Паттерн в формате pattern;pattern;… | -Djdk.serialFilter="!*" (запрет всех), com.example.*;maxdepth=5 |
java.util.concurrent.ForkJoinPool.common.parallelism | Размер пула потоков ForkJoinPool.commonPool() | Целое число ≥ 1 | -Djava.util.concurrent.ForkJoinPool.common.parallelism=4 |
sun.java2d.opengl | Использовать OpenGL для Java2D | true, false, True, False | -Dsun.java2d.opengl=True |
awt.useSystemAAFontSettings | Сглаживание шрифтов в AWT/Swing | on, off, gasp, lcd, lcd_hrgb, lcd_vrgb | -Dawt.useSystemAAFontSettings=lcd |
swing.aatext | Сглаживание шрифтов в Swing | true, false | -Dswing.aatext=true |
sun.java.launcher.pid | PID родительского процесса-запускателя (только чтение) | Целое число | — |
⚠️ Свойства, начинающиеся с
sun.*илиcom.sun.*, не являются частью официальной спецификации Java SE. Их поведение может меняться между реализациями (OpenJDK, Oracle JDK, Azul, IBM Semeru и др.).
1.2. Нестандартные -X параметры
Эти параметры реализованы в OpenJDK и совместимых сборках. Часть из них стабильна, часть устарела или удалена в новых версиях.
| Параметр | Описание | Значения / Примеры |
|---|---|---|
-Xms<size> | Начальный размер heap-памяти | -Xms256m, -Xms1g, -Xms4096m |
-Xmx<size> | Максимальный размер heap-памяти | -Xmx2g, -Xmx8192m |
-Xss<size> | Размер стека одного потока | -Xss512k, -Xss1m (по умолчанию: ~1 МБ на x64) |
-Xmn<size> | Размер молодого поколения (young generation) | -Xmn1g — эквивалентно -XX:NewSize=1g -XX:MaxNewSize=1g |
-Xnoclassgc | Отключение сборки мусора классов (устаревшее, игнорируется в новых версиях) | — |
-Xverify:<mode> | Проверка байткода (устарело в Java 13+) | remote, all, none — но в новых версиях всегда all или none, remote удалён |
| `-Xshare:auto | on | off` |
-Xloggc:<file> | Логирование GC в файл (устарело в Java 9+, заменено -Xlog:gc*) | -Xloggc:gc.log |
-Xprof | Встроенный профайлер (устарело в Java 14, удалено в 15) | — |
-Xdebug, -Xrunjdwp | Поддержка JDWP (устарело, заменено -agentlib:jdwp) | -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005 |
-Xcomp, -Xint, -Xmixed | Режим JIT-компиляции | -Xcomp — компилировать всё сразу; -Xint — интерпретировать всё; -Xmixed — по умолчанию (гибрид) |
1.3. Экспериментальные -XX параметры
Эти параметры доступны через -XX:+OptionName, -XX:-OptionName, -XX:OptionName=value.
1.3.1. Память и GC
| Параметр | Описание | Значения / Примеры |
|---|---|---|
-XX:+UseSerialGC | Последовательный GC (однопоточный) | Подходит для малых heap и одноядерных сред |
-XX:+UseParallelGC | Parallel GC («пропускная способность») | По умолчанию в Oracle JDK ≤ 8 и в режиме -server |
-XX:+UseParallelOldGC | Включает Parallel Old для старшего поколения (актуально только если используется Parallel GC) | Включается автоматически при -XX:+UseParallelGC |
-XX:+UseConcMarkSweepGC | CMS GC (устарело в Java 9, удалено в 14) | — |
-XX:+UseG1GC | G1 GC (Garbage-First) | По умолчанию в Java 9–16 |
-XX:+UseZGC | Z Garbage Collector | Требует -XX:+UnlockExperimentalVMOptions до Java 15; начиная с Java 15 — без флага |
-XX:+UseShenandoahGC | Shenandoah GC | Обычно требует сборки OpenJDK с поддержкой Shenandoah |
-XX:MaxGCPauseMillis=<ms> | Целевая максимальная пауза GC (влияет на G1, Z, Shenandoah) | -XX:MaxGCPauseMillis=200 |
-XX:G1HeapRegionSize=<size> | Размер региона G1 | 1m, 2m, 4m, 8m, 16m, 32m (по умолчанию вычисляется) |
-XX:G1NewSizePercent=5, -XX:G1MaxNewSizePercent=60 | Мин/макс доля heap под молодое поколение в G1 | Проценты от общей heap |
-XX:InitiatingHeapOccupancyPercent=45 | Порог запуска concurrent cycle в G1 | Процент заполнения heap |
-XX:+AlwaysPreTouch | Выделение и «трогание» всей heap при старте | Уменьшает фрагментацию, увеличивает время старта |
-XX:+UseCompressedOops | Использование сжатых указателей (64-битный режим) | Включено по умолчанию при heap ≤ 32 ГБ |
-XX:ObjectAlignmentInBytes=<n> | Выравнивание объектов (только с +UseCompressedOops) | Степень двойки, ≥ 8, ≤ 256; по умолчанию 8 |
-XX:+UseLargePages | Использование huge pages (требует ОС-поддержки) | +UseLargePages + настройка vm.nr_hugepages в Linux |
1.3.2. JIT и компиляция
| Параметр | Описание |
|---|---|
-XX:+TieredCompilation | Многоуровневая компиляция (C1 + C2) — по умолчанию с Java 8 |
-XX:TieredStopAtLevel=1..4 | Уровень остановки компиляции (1 — интерпретатор + C1 без профилирования, 4 — C2) |
-XX:CompileThreshold=10000 | Кол-во вызовов метода до компиляции C1 (для -XX:-TieredCompilation) |
-XX:ReservedCodeCacheSize=240m | Макс. размер кэша скомпилированного кода |
-XX:+PrintCompilation | Вывод информации о компиляции в stderr |
-XX:+UnlockDiagnosticVMOptions | Разблокировка диагностических опций (для -XX:+PrintAssembly, -XX:+LogCompilation, и др.) |
-XX:+PrintAssembly | Дизассемблирование скомпилированного кода (требует hsdis библиотеки) |
-XX:CICompilerCount=<n> | Количество потоков JIT-компилятора |
-XX:+BackgroundCompilation | Фоновая компиляция (по умолчанию включена) |
1.3.3. Class Data Sharing (CDS)
| Параметр | Описание |
|---|---|
-XX:SharedArchiveFile=<file> | Путь к архиву CDS (classes.jsa) |
-XX:+UnlockDiagnosticVMOptions -XX:SharedArchiveFile=app.jsa -Xshare:dump | Генерация кастомного архива |
-XX:ArchiveClassesAtExit=<file> | Автоматическое создание архива при завершении JVM |
1.3.4. JFR (Java Flight Recorder)
| Параметр | Описание |
|---|---|
-XX:+FlightRecorder | Включение JFR (по умолчанию включён в OpenJDK ≥ 11) |
-XX:StartFlightRecording=settings=<profile>,filename=<file.jfr>,duration=60s | Запуск записи при старте |
-XX:FlightRecorderOptions=repository=<dir>,maxsize=1g | Настройка хранилища и лимитов |
1.3.5. Отладка и диагностика
| Параметр | Описание |
|---|---|
-XX:+HeapDumpOnOutOfMemoryError | Создание heap-дампа при OutOfMemoryError |
-XX:HeapDumpPath=/path/to/dump.hprof | Путь для heap-дампа |
-XX:ErrorFile=/path/to/hs_err_pid%p.log | Лог ошибок JVM при крахе |
-XX:+PrintGC, -XX:+PrintGCDetails, -XX:+PrintGCDateStamps | Подробное логирование GC (устарело в Java 9+, заменено -Xlog:gc*) |
-XX:+PrintCommandLineFlags | Вывод всех нестандартных флагов при старте |
-XX:+TraceClassLoading, -XX:+TraceClassUnloading | Трассировка загрузки/выгрузки классов |
-XX:+UseGCLogFileRotation, -XX:NumberOfGCLogFiles=5, -XX:GCLogFileSize=10M | Ротация GC-логов (устарело, заменено -Xlog:gc*:file=gc.log:time,filecount=5,filesize=10M) |
1.4. Современное логирование GC и JVM через -Xlog (Java 9+)
Синтаксис:
-Xlog:[<selectors>][:[output][:[decorators][:output-options]]]
Селекторы (что логировать):
gc: сборка мусораgc+age=trace,gc+heap=debug,gc+metaspace=info,jit,class,safepoint,os,jfr,monitorinflation,modulesall=trace: всё на уровнеtrace
Выходы:
stdout,stderr,file=filename,file=filename%t(временная метка),file=filename%p(PID)
Декораторы:
time,utctime,uptime,timemillis,timenanos,pid,tid,level,tags
Примеры:
# Полный GC-лог с ротацией
-Xlog:gc*:file=gc.log:time,uptime,level,tags:filecount=5,filesize=20M
# JIT-компиляция и инлайнинг
-Xlog:jit+compilation=info,jit+inlining=debug:file=jit.log
# Загрузка модулей и классов
-Xlog:class+load=info,modules=info:stdout
# JFR-события в реальном времени (требует JFR)
-Xlog:jfr*=trace:stdout
2. Системные свойства среды выполнения
Системные свойства — это ключ-значение пары, доступные внутри JVM через System.getProperty(String key). Они формируются из нескольких источников и имеют иерархию приоритетов:
- Значения по умолчанию, заданные реализацией JVM (например,
os.name,java.version); - Параметры
-Dkey=value, переданные при запуске; - Программные вызовы
System.setProperty(String key, String value)— действуют только после выполнения, не влияют на уже инициализированные подсистемы; - Переменные окружения — не становятся системными свойствами автоматически, но некоторые свойства считывают их значения при инициализации (например,
java.homeзависит отJAVA_HOME, если JVM запущена черезjavalauncher).
Системные свойства можно разделить по функциональным группам.
2.1. Свойства, описывающие среду выполнения
Эта группа фиксирована, доступна только для чтения, устанавливается JVM при старте.
| Свойство | Описание | Пример значения |
|---|---|---|
java.version | Версия Java (JRE) | 17.0.12 |
java.runtime.version | Полная версия JRE (включая сборку) | 17.0.12+7-Ubuntu-122.04 |
java.vm.version | Версия JVM (HotSpot) | 17.0.12+7-Ubuntu-122.04 |
java.vm.vendor | Поставщик JVM | Ubuntu, Eclipse Adoptium, Azul Systems, Inc. |
java.vm.name | Название JVM | OpenJDK 64-Bit Server VM |
java.vm.specification.version | Версия спецификации JVM | 17 |
java.specification.version | Версия спецификации Java SE | 17 |
java.specification.vendor | Поставщик спецификации | Oracle Corporation |
java.vendor | Поставщик реализации JRE | Eclipse Adoptium |
java.vendor.url | Ссылка на сайт поставщика | https://adoptium.net/ |
java.home | Корневой каталог JRE | /usr/lib/jvm/java-17-openjdk-amd64 |
java.class.version | Версия формата .class | 61.0 (Java 17 → 61, Java 21 → 65) |
2.2. Свойства операционной системы и аппаратуры
| Свойство | Описание | Пример значения |
|---|---|---|
os.name | Название ОС | Linux, Windows 10, Mac OS X |
os.version | Версия ОС | 5.15.0-101-generic, 10.0, 14.5 |
os.arch | Архитектура процессора | amd64, aarch64, x86, ppc64le |
sun.arch.data.model | Разрядность данных (32/64) | 64 |
sun.cpu.isalist | Поддерживаемые инструкции CPU (x86) | sse4.2,aes |
sun.cpu.endian | Порядок байтов | little, big |
⚠️
sun.*свойства непереносимы — их отсутствие возможно в альтернативных реализациях (например, GraalVM Native Image).
2.3. Пользователь и локаль
| Свойство | Описание | Значения | Примечание |
|---|---|---|---|
user.name | Имя текущего пользователя ОС | timur, Administrator | Берётся из системного вызова getpwuid / GetUserName |
user.home | Домашняя директория | /home/timur, C:\Users\Timur | |
user.dir | Текущая рабочая директория при запуске | /opt/app, D:\project | Меняется при System.setProperty("user.dir", …) не влияет на File без абсолютного пути — поведение не определено |
user.language | Язык локали по умолчанию | en, ru, zh | Может отличаться от Locale.getDefault().getLanguage() после изменения локали |
user.country, user.region | Страна/регион | US, RU, CN | |
user.variant | Вариант локали | POSIX, WIN, EURO | |
file.separator | Разделитель пути | /, \ | Константа, не меняется |
path.separator | Разделитель путей в CLASSPATH | :, ; | |
line.separator | Символ(ы) конца строки | \n, \r\n |
2.4. Свойства ввода-вывода и кодировок
| Свойство | Описание | Значения по умолчанию | Примечание |
|---|---|---|---|
file.encoding | Кодировка по умолчанию для FileReader, FileWriter, PrintStream, PrintWriter без явной кодировки | UTF-8 (Java ≥ 18), ранее ANSI_X3.4-1968 (ASCII) или системная | Важно: в Java 17 и ранее это могло быть Cp1251 на Windows-локали ru_RU. С Java 18 — всегда UTF-8, если не переопределено через -Dfile.encoding=… |
sun.stdout.encoding, sun.stderr.encoding | Кодировка System.out и System.err | То же, что file.encoding, но может быть переопределено отдельно | Учитываются только при создании PrintStream внутри JVM, до первого использования System.out |
native.encoding | Кодировка ОС для нативных вызовов (например, имен файлов) | UTF-8, Cp1251, KOI8-R | Доступно с Java 17+, используется в Path.of(String) и Files при работе с не-UTF-8 именами |
sun.jnu.encoding | Кодировка для аргументов командной строки и имён файлов в JNI | То же, что native.encoding |
2.5. Свойства сети
Эти свойства влияют на поведение java.net API.
| Свойство | Описание | Типичные значения |
|---|---|---|
http.proxyHost | Хост HTTP-прокси | proxy.company.com, 192.168.1.10 |
http.proxyPort | Порт HTTP-прокси | 3128, 8080 |
https.proxyHost, https.proxyPort | То же для HTTPS | |
http.nonProxyHosts | Список хостов, к которым прокси не применяется | `localhost |
ftp.proxyHost, ftp.proxyPort | FTP-прокси | |
socksProxyHost, socksProxyPort | SOCKS-прокси (версия 5) | |
java.net.useSystemProxies | Использовать системные настройки прокси (только на Windows/macOS) | true, false |
networkaddress.cache.ttl | Время жизни кэша DNS-имён (секунды) | -1 — кэшировать вечно, 30 — 30 сек, 0 — не кэшировать |
networkaddress.cache.negative.ttl | TTL для отрицательных DNS-запросов | 10 по умолчанию |
sun.net.inetaddr.ttl | Устаревшее, эквивалентно networkaddress.cache.ttl | |
java.net.preferIPv4Stack | Использовать IPv4 при наличии дуального стека | true, false |
java.net.preferIPv6Addresses | Предпочитать IPv6-адрес при разрешении имён | true, false |
jdk.net.URLClassPath.disableNonFileURLs | Запрет загрузки классов по не-file URL | true, false |
⚠️ Прокси-настройки применяются только к
HttpURLConnection,URL.openConnection(). Клиенты вродеHttpClient(Java 11+) илиOkHttpне используют их — требуют явной конфигурацииProxySelector.
2.6. Свойства безопасности
| Свойство | Описание |
|---|---|
java.security.manager | Включение SecurityManager (устарело в Java 17, удалено в 18) |
java.security.policy | Путь к файлу политики безопасности (актуально только при наличии SecurityManager) |
java.security.auth.login.config | Файл конфигурации JAAS |
java.security.krb5.conf | Путь к krb5.conf для Kerberos |
javax.net.ssl.trustStore, javax.net.ssl.trustStoreType, javax.net.ssl.trustStorePassword | Параметры доверенного хранилища |
javax.net.ssl.keyStore, javax.net.ssl.keyStoreType, javax.net.ssl.keyStorePassword | Параметры клиентского хранилища ключей |
javax.net.ssl.keyStoreProvider | Провайдер хранилища |
javax.net.debug | Отладка SSL/TLS соединений |
2.7. Свойства локализации и форматирования
| Свойство | Описание | Пример |
|---|---|---|
user.timezone | Часовой пояс по умолчанию | UTC, Europe/Moscow |
java.locale.providers | Порядок провайдеров локализации (Java 9+) | COMPAT,SPI,CLDR,JRE — приоритет от левого к правому |
java.util.PropertyResourceBundle.encoding | Кодировка .properties файлов | ISO-8859-1 (по умолчанию), UTF-8 (начиная с Java 9, если файл содержит  BOM или указано явно) |
🔹 Начиная с Java 9,
PropertyResourceBundleподдерживает UTF-8 без экранирования, если файл сохранён в UTF-8 с BOM или указано-Djava.util.PropertyResourceBundle.encoding=UTF-8.
2.8. Свойства параллелизма
| Свойство | Описание | Значение по умолчанию |
|---|---|---|
java.util.concurrent.ForkJoinPool.common.parallelism | Размер ForkJoinPool.commonPool() | Runtime.getRuntime().availableProcessors() - 1, минимум 1 |
java.util.concurrent.ForkJoinPool.common.exceptionHandler | Класс обработчика исключений (FQCN) | — |
java.util.concurrent.ForkJoinPool.common.threadFactory | Класс ThreadFactory (FQCN) | — |
Пример:
-Djava.util.concurrent.ForkJoinPool.common.parallelism=4
-Djava.util.concurrent.ForkJoinPool.common.threadFactory=com.example.CustomThreadFactory
2.9. Свойства GUI (AWT/Swing)
| Свойство | Описание | Примеры |
|---|---|---|
awt.toolkit | Класс AWT Toolkit | sun.awt.X11.XToolkit, sun.awt.windows.WToolkit |
swing.defaultlaf | Look-and-Feel по умолчанию | javax.swing.plaf.metal.MetalLookAndFeel, com.sun.java.swing.plaf.gtk.GTKLookAndFeel |
swing.metalTheme | Тема Metal L&F | steel, ocean |
awt.useSystemAAFontSettings | Сглаживание шрифтов | on, off, gasp, lcd, lcd_hrgb |
swing.aatext | Включение сглаживания в Swing | true, false |
sun.java2d.opengl | Использовать OpenGL для рендеринга | True, False |
sun.java2d.d3d | Использовать Direct3D (Windows) | True, False |
sun.java2d.noddraw | Отключить DirectDraw (Windows) | true, false |
🔹 Эти свойства влияют только на приложения с GUI. На серверных JVM (headless) они игнорируются.
2.10. Свойства, управляемые переменными окружения
Некоторые системные свойства инициализируются на основе переменных окружения при старте JVM:
| Переменная окружения | Влияющее свойство | Примечание |
|---|---|---|
JAVA_HOME | java.home | Только если java запущен как $JAVA_HOME/bin/java |
CLASSPATH | java.class.path | Переопределяется опцией -cp или -classpath |
TMPDIR (Unix), TEMP, TMP (Windows) | java.io.tmpdir | Приоритет: TMPDIR > TEMP > TMP |
LANG, LC_ALL, LC_CTYPE | user.language, user.country, file.encoding, sun.jnu.encoding | JVM парсит локаль из LANG=en_US.UTF-8 → user.language=en, user.country=US, file.encoding=UTF-8 |
Пример:
LANG=ru_RU.UTF-8 LC_ALL=ru_RU.UTF-8 java -jar app.jar
# → user.language=ru, user.country=RU, file.encoding=UTF-8
2.11. Динамические свойства: System.setProperty
Метод System.setProperty(String key, String value) изменяет значение свойства во время выполнения. Однако:
- Не все подсистемы реагируют на изменения после инициализации (например,
file.encodingигнорируется после первого созданияInputStreamReader); - Свойства безопасности (например,
java.security.policy) не перечитываются; - Изменение
user.dirне влияет на поведениеnew File("file.txt")— относительные пути разрешаются на уровне ОС при вызовеopen(), а не внутри JVM.
Рекомендуется устанавливать конфигурационные свойства до инициализации зависимых компонентов.
3. Конфигурация безопасности
Подсистема безопасности Java включает несколько взаимосвязанных компонентов:
- Java Cryptography Architecture (JCA) — криптографические сервисы;
- Java Secure Socket Extension (JSSE) — TLS/SSL;
- Java Authentication and Authorization Service (JAAS) — аутентификация и авторизация;
- Java Generic Security Services (JGSS) — Kerberos, SPNEGO;
- Policy-based и Module-based ограничения доступа — управление разрешениями;
- Security Manager — устаревший механизм контроля доступа (удалён в Java 18);
- Security Properties — глобальные настройки через
java.security.
Все настройки управляются через:
- файл
$JAVA_HOME/conf/security/java.security(ранее$JAVA_HOME/lib/security/java.security); - файлы политики:
java.policy,java.security.policy, пользовательские.policy; - системные свойства (
-D…); - программные вызовы (
Security.addProvider,Policy.setPolicy); - параметры запуска (
-Djava.security.manager,-Djava.security.policy).
3.1. Файл java.security
Расположение:
$JAVA_HOME/conf/security/java.security(Java ≥ 9)$JAVA_HOME/lib/security/java.security(Java ≤ 8)
Это основной конфигурационный файл JVM. Он содержит директивы вида key=value, комментарии (#), и поддерживает переменные (${java.home}).
3.1.1. Провайдеры криптографии (security.provider.N)
Порядок провайдеров определяет приоритет при поиске реализации алгоритмов.
security.provider.1=SUN
security.provider.2=SunRsaSign
security.provider.3=SunEC
security.provider.4=SunJSSE
security.provider.5=SunJCE
security.provider.6=SunJGSS
security.provider.7=SunSASL
security.provider.8=XMLDSig
security.provider.9=SunPCSC
security.provider.10=JDKPSS # начиная с Java 11
Наиболее важные провайдеры:
| Провайдер | Описание |
|---|---|
SUN | Реализация MessageDigest (SHA-1, SHA-256), SecureRandom, Signature (SHA1withDSA), KeyStore (JKS), Policy |
SunRsaSign | Подписи RSA: SHA256withRSA, SHA512withRSA |
SunEC | Криптография на эллиптических кривых: EC, ECDH, ECDSA, secp256r1, secp384r1 |
SunJSSE | Реализация JSSE: SSLContext, KeyManagerFactory, TrustManagerFactory |
SunJCE | Симметричные алгоритмы: AES, DES, DESede, HmacSHA256, PBE, Cipher (GCM, CBC), KeyGenerator, SecretKeyFactory |
SunJGSS | GSS-API/Kerberos v5 |
Добавление стороннего провайдера (например, Bouncy Castle):
security.provider.11=org.bouncycastle.jce.provider.BouncyCastleProvider
Или программно:
Security.insertProviderAt(new BouncyCastleProvider(), 1);
3.1.2. Алгоритмы, отключённые по умолчанию
| Параметр | Описание | Пример значения |
|---|---|---|
jdk.tls.disabledAlgorithms | Алгоритмы, запрещённые в TLS | SSLv3, TLSv1, TLSv1.1, RC4, DES, MD5withRSA, DH keySize < 1024, EC keySize < 224, 3DES_EDE_CBC |
jdk.certpath.disabledAlgorithms | Алгоритмы, запрещённые при проверке сертификатов | MD2, MD5, SHA1 jdkCA & usage TLSServer, RSA keySize < 1024, DSA keySize < 1024 |
jdk.jar.disabledAlgorithms | Алгоритмы, запрещённые в подписях JAR | То же, что certpath, плюс SHA1 при определённых условиях |
jdk.security.provider.preferred | Предпочтительные провайдеры для алгоритмов | SHA256withRSA:SUN, AES/GCM/NoPadding:SunJCE |
Формат значений — список условий через запятую. Поддерживает:
keySize < N,keySize > N& usage …— применение (например,& usage TLSServer)& jdkCA— если сертификат выпущен доверенным CA изcacerts
Пример:
jdk.tls.disabledAlgorithms=SSLv3, TLSv1, RC4, DH keySize < 2048, EC keySize < 256
3.1.3. Генератор случайных чисел
| Параметр | Описание |
|---|---|
securerandom.source | Источник энтропии для SecureRandom.getInstanceStrong() |
securerandom.strongAlgorithms | Алгоритмы, считающиеся «сильными» |
🔹
new SecureRandom()без аргументов используетNativePRNG(на базе/dev/urandom) — неблокирующий.
🔹SecureRandom.getInstanceStrong()используетNativePRNGBlocking(на базе/dev/random) — может блокироваться при нехватке энтропии.
3.1.4. Хранилища сертификатов
| Параметр | Описание | Значение по умолчанию |
|---|---|---|
javax.net.ssl.trustStore | Системное хранилище доверенных сертификатов | ${java.home}/lib/security/cacerts |
javax.net.ssl.trustStoreType | Тип хранилища | JKS, PKCS12 (по умолчанию JKS) |
javax.net.ssl.trustStoreProvider | Провайдер хранилища | SUN |
javax.net.ssl.keyStore | Клиентское хранилище ключей | — |
ssl.KeyManagerFactory.algorithm | Алгоритм KeyManagerFactory | SunX509, PKIX |
ssl.TrustManagerFactory.algorithm | Алгоритм TrustManagerFactory | PKIX, SunX509 |
Файл cacerts содержит корневые сертификаты Let’s Encrypt, DigiCert, GlobalSign и др. Его можно обновить через keytool -importcert.
3.1.5. Политики безопасности
| Параметр | Описание |
|---|---|
policy.provider | Класс реализации Policy |
policy.url.1, policy.url.2, … | Список URL файлов политики |
policy.allowSystemProperty | Разрешить подстановку системных свойств в .policy |
policy.expandProperties | Разрешить ${…} в путях в .policy |
3.1.6. JAAS (аутентификация)
| Параметр | Описание |
|---|---|
login.configuration.provider | Класс загрузчика конфигурации JAAS |
java.security.auth.login.config | Путь к jaas.conf |
3.1.7. Отладка
| Свойство | Эффект |
|---|---|
-Djava.security.debug=… | Включает детальное логирование подсистемы |
| Возможные значения: | |
access | Проверки SecurityManager (устаревшее) |
certpath | Построение и проверка цепочки сертификатов |
jar | Проверка подписей JAR |
logincontext | JAAS: логин-модули, callback |
configfile | Загрузка jaas.conf |
provider | Регистрация провайдеров |
pkcs11 | Работа с PKCS#11 |
all | Всё |
Пример:
-Djava.security.debug=certpath,logincontext
3.2. Файлы политики (.policy)
Формат:
grant [CodeSource] [, Principal ...] {
Permission permission_class ["target"] [, "action"] [, signedBy "signer"];
};
3.2.1. Элементы grant
CodeSource: источник кода —codeBase "URL"+ опциональноsignedBy "alias".codeBase "file:/opt/app/"— локальные классы;codeBase "http://example.com/"— удалённые;codeBase "file:${user.home}/"— переменные разрешаются.
Principal: субъект (JAAS), напримерPrincipal com.sun.security.auth.UnixPrincipal "timur".
3.2.2. Типы разрешений (Permission)
| Класс | Описание | Пример |
|---|---|---|
java.io.FilePermission | Доступ к файловой системе | new FilePermission("/tmp/-", "read,write,delete") |
java.net.SocketPermission | Сетевые соединения | new SocketPermission("example.com:443", "connect,resolve") |
java.lang.RuntimePermission | Операции среды выполнения | new RuntimePermission("exitVM"), "getClassLoader", "setFactory", "accessClassInPackage.sun.misc" |
java.lang.reflect.ReflectPermission | Рефлексия | new ReflectPermission("suppressAccessChecks") |
java.security.SecurityPermission | Изменение security-подсистемы | new SecurityPermission("putProviderProperty.SunJCE") |
java.util.PropertyPermission | Чтение/запись системных свойств | new PropertyPermission("file.encoding", "read") |
java.net.NetPermission | Сетевые настройки | new NetPermission("specifyStreamHandler"), "getProxySelector" |
javax.sound.sampled.AudioPermission | Доступ к аудио | new AudioPermission("play") |
javax.security.auth.AuthPermission | JAAS-операции | new AuthPermission("createLoginContext.myContext") |
java.security.AllPermission | Полный доступ (только для доверенного кода) | new AllPermission() |
Шаблоны в FilePermission и SocketPermission:
/tmp/-—/tmpи все подкаталоги;/tmp/*— только файлы в/tmp, без подкаталогов;"*.example.com:443"— все поддомены на порту 443;"localhost:1024-"— порты ≥ 1024.
3.2.3. Пример файла политики
grant codeBase "file:/opt/app/lib/-" {
permission java.io.FilePermission "/tmp/app.log", "write";
permission java.net.SocketPermission "api.example.com:443", "connect,resolve";
permission java.util.PropertyPermission "user.timezone", "read";
permission java.lang.RuntimePermission "accessDeclaredMembers";
};
grant codeBase "file:${java.home}/lib/ext/-" {
permission java.security.AllPermission;
};
grant Principal com.sun.security.auth.UnixPrincipal "timur" {
permission javax.security.auth.AuthPermission "doAs";
};
Загрузка:
java -Djava.security.manager -Djava.security.policy==/opt/app/app.policy MyApp
(два = означают только этот файл, один = — добавить к системным).
3.3. JAAS: jaas.conf
Формат:
AppName {
com.sun.security.auth.module.KeyStoreLoginModule required
keyStoreURL="file:/keystore.jks"
keyStorePassword="secret";
com.sun.security.auth.module.UnixLoginModule sufficient;
};
Типы модулей:
required— должен завершиться успешно, но не прерывает цепочку при ошибке;requisite— при ошибке — сразу отказ;sufficient— при успехе — цепочка завершается успешно;optional— игнорируется, если другие модули успешны.
Встроенные модули:
| Модуль | Назначение |
|---|---|
KeyStoreLoginModule | Аутентификация по ключу из JKS/PKCS12 |
UnixLoginModule | Аутентификация через PAM (Linux/macOS) |
NTLoginModule | Аутентификация в Active Directory (Windows) |
Krb5LoginModule | Аутентификация через Kerberos |
Пример Kerberos:
KafkaClient {
com.sun.security.auth.module.Krb5LoginModule required
useKeyTab=true
keyTab="/etc/security/keytabs/app.keytab"
principal="app/host@REALM"
storeKey=true
useTicketCache=false;
};
3.4. JSSE: TLS/SSL-конфигурация
3.4.1. Программная настройка SSLContext
KeyStore trustStore = KeyStore.getInstance("JKS");
try (InputStream in = Files.newInputStream(Paths.get("trust.jks"))) {
trustStore.load(in, "changeit".toCharArray());
}
TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX");
tmf.init(trustStore);
SSLContext sslContext = SSLContext.getInstance("TLSv1.3");
sslContext.init(null, tmf.getTrustManagers(), null);
3.4.2. Системные свойства для JSSE
| Свойство | Описание |
|---|---|
https.protocols | Протоколы для HttpsURLConnection |
https.cipherSuites | Разрешённые шифронаборы |
jdk.tls.client.protocols | Протоколы для всех клиентских сокетов |
jdk.tls.server.protocols | Протоколы для серверных сокетов |
jdk.tls.ephemeralDHKeySize | Размер ключа DH для обмена |
jdk.tls.namedGroups | Разрешённые эллиптические кривые |
3.4.3. Отладка TLS
-Djavax.net.debug=ssl:handshake:keygen:verbose
Уровни: ssl, handshake, keygen, session, defaultctx, all.
3.5. Устаревшее: SecurityManager
- Включался через
-Djava.security.manager(Java ≤ 17); - Все проверки
checkPermission()вызывалиSecurityManager.check…(); - Удалён в Java 18: вызов
System.setSecurityManager()выбрасываетUnsupportedOperationException; - Рекомендуемая замена: модульные ограничения (
--limit-modules,--add-exports,--add-opens),AccessController.doPrivileged(остался, но безSecurityManagerработает как no-op), проверки на уровне приложения/контейнера.
3.6. Криптографические ограничения: JCE Jurisdiction Policy Files
До Java 8 требовались отдельные US_export_policy.jar, local_policy.jar для неограниченной криптографии.
Начиная с Java 8u161 и Java 9 — неограниченные политики включены по умолчанию. Проверка:
int maxKeyLen = Cipher.getMaxAllowedKeyLength("AES");
System.out.println(maxKeyLen); // 2147483647 → неограничено
4. Логирование
В Java логирование реализуется через иерархию фасадов и движков. Основные компоненты:
- API — интерфейсы (
Logger,Level,Handler); - Фасады — абстракции над движками (SLF4J);
- Движки — реализации (
java.util.logging, Logback, Log4j 2); - Мосты — перенаправление вызовов между движками (
jul-to-slf4j,log4j-to-slf4j); - Форматы и транспорты —
PatternLayout, JSON, GELF, syslog, Kafka, HTTP; - Контекст — MDC (Mapped Diagnostic Context), NDLC (Nested Diagnostic Logical Context).
4.1. java.util.logging (JUL)
Встроен в Java SE. Конфигурация — через $JAVA_HOME/conf/logging.properties (Java ≥ 9) или программно.
4.1.1. Иерархия логгеров
- Корневой логгер:
""(пустая строка), эквивалентенLogger.getLogger(""); - Иерархия строится по точкам:
com.example.service→ родительcom.example→com→""; - Уровень логгера наследуется от ближайшего предка с установленным уровнем.
4.1.2. Уровни (Level)
| Уровень | Числовое значение | Назначение |
|---|---|---|
OFF | Integer.MAX_VALUE | Отключение логирования |
SEVERE | 1000 | Критические ошибки (исключения, сбои) |
WARNING | 900 | Предупреждения (потенциально некорректное поведение) |
INFO | 800 | Информационные сообщения (старт, завершение, ключевые события) |
CONFIG | 700 | Конфигурационная информация (версии, параметры) |
FINE | 500 | Отладка уровня сервиса |
FINER | 400 | Подробная отладка |
FINEST | 300 | Наиболее детальная отладка |
ALL | Integer.MIN_VALUE | Всё |
Программное управление:
Logger logger = Logger.getLogger("com.example");
logger.setLevel(Level.FINE);
4.1.3. Обработчики (Handler)
| Класс | Описание |
|---|---|
ConsoleHandler | Вывод в System.err |
FileHandler | Запись в файл, поддерживает ротацию (%u, %g, %t) |
StreamHandler | Произвольный OutputStream |
SocketHandler | Отправка в TCP-сокет (устаревший, без TLS) |
MemoryHandler | Буферизация в памяти с триггером сброса |
AsyncHandler (Java 19+) | Асинхронная обработка (экспериментальный) |
Параметры FileHandler:
java.util.logging.FileHandler.pattern = %h/java%u.log
java.util.logging.FileHandler.limit = 5242880 # 5 МБ
java.util.logging.FileHandler.count = 5 # 5 файлов
java.util.logging.FileHandler.formatter = java.util.logging.SimpleFormatter
java.util.logging.FileHandler.append = true
4.1.4. Форматтеры (Formatter)
| Класс | Формат вывода |
|---|---|
SimpleFormatter | мар 13, 2025 10:05:30 ДП com.example.Main main WARNING: Message |
XMLFormatter | XML-структура лог-записи |
LogRecord.toString() | Сырой вывод (для отладки) |
Кастомный SimpleFormatter через шаблон (Java 7+):
java.util.logging.SimpleFormatter.format=%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS.%1$tL %4$-7s [%3$s] %5$s%6$s%n
Где:
%1$t — время (LogRecord.getMillis),
%2$s — имя логгера,
%3$s — имя потока,
%4$s — уровень,
%5$s — сообщение,
%6$s — исключение (если есть),
%n — системный перевод строки.
4.1.5. Фильтры (Filter)
Интерфейс java.util.logging.Filter:
public boolean isLoggable(LogRecord record) {
return !record.getMessage().contains("password");
}
Устанавливается на логгер или хендлер:
logger.setFilter(filter);
consoleHandler.setFilter(filter);
4.1.6. Глобальная конфигурация: logging.properties
Расположение: $JAVA_HOME/conf/logging.properties
Пример:
handlers=java.util.logging.ConsoleHandler,java.util.logging.FileHandler
.level=INFO
java.util.logging.ConsoleHandler.level=WARNING
java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter
com.example.level=FINE
com.example.handlers=java.util.logging.FileHandler
com.example.useParentHandlers=false
Загрузка альтернативного файла:
-Djava.util.logging.config.file=/opt/app/logging.properties
4.2. SLF4J (Simple Logging Facade for Java)
Фасад, не реализующий логирование, а делегирующий вызовы движку.
4.2.1. API
Logger logger = LoggerFactory.getLogger(MyClass.class);
logger.trace("Detailed trace");
logger.debug("Debug info: {}", value);
logger.info("Operation started");
logger.warn("Potential issue: {}", cause);
logger.error("Failure", exception);
Методы:
trace(),debug(),info(),warn(),error()— 12 перегрузок на каждый уровень (с объектами, массивами, исключениями);- Поддержка параметризации:
{}заменяетсяString.valueOf(arg); - Поддержка
Supplier<String>(Java 8+):logger.debug(() -> computeExpensiveMessage()).
4.2.2. Привязка к движку
SLF4J выбирает движок по наличию JAR-файла META-INF/services/org/slf4j/impl/StaticLoggerBinder:
| JAR | Движок |
|---|---|
slf4j-simple-*.jar | Простая реализация (вывод в System.err, уровень INFO) |
slf4j-jdk14-*.jar | Привязка к java.util.logging |
logback-classic-*.jar | Logback (рекомендуется) |
slf4j-log4j12-*.jar | Log4j 1.2 (устарело) |
log4j-slf4j-impl-*.jar | Log4j 2 |
Только один StaticLoggerBinder должен быть в classpath — иначе ошибка инициализации.
4.2.3. Мосты
| Артефакт | Назначение |
|---|---|
jul-to-slf4j | Перенаправление JUL → SLF4J (через SLF4JBridgeHandler) |
log4j-over-slf4j | Замена Log4j 1.2 API → SLF4J |
jcl-over-slf4j | Замена Jakarta Commons Logging → SLF4J |
Активация JUL → SLF4J:
SLF4JBridgeHandler.removeHandlersForRootLogger();
SLF4JBridgeHandler.install();
4.3. Logback
Реализация SLF4J, разработанная тем же автором (Ceki Gülcü). Конфигурация: logback.xml, logback.groovy, logback-test.xml.
4.3.1. Структура logback.xml
<configuration scan="true" scanPeriod="30 seconds">
<contextListener class="ch.qos.logback.classic.jul.LevelChangePropagator">
<resetJUL>true</resetJUL>
</contextListener>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>app.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>app.%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
<maxFileSize>100MB</maxFileSize>
<maxHistory>30</maxHistory>
<totalSizeCap>3GB</totalSizeCap>
</rollingPolicy>
<encoder>
<pattern>%d{ISO8601} [%thread] %-5level %logger{40} [%X{traceId}] - %msg%n</pattern>
</encoder>
</appender>
<logger name="com.example.service" level="DEBUG" additivity="false">
<appender-ref ref="FILE"/>
</logger>
<root level="INFO">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="FILE"/>
</root>
</configuration>
4.3.2. Appenders
| Класс | Описание |
|---|---|
ConsoleAppender | Вывод в System.out/System.err |
FileAppender | Запись в файл (без ротации) |
RollingFileAppender | Файл с ротацией (требует RollingPolicy) |
SMTPAppender | Отправка email при ERROR/WARN |
DBAppender | Запись в БД (таблицы logging_event, logging_event_property, logging_event_exception) |
SyslogAppender | Отправка в syslog (RFC 3164/5424) |
KafkaAppender (через logback-kafka-appender) | Отправка в Kafka |
AsyncAppender | Оборачивает другие appenders в асинхронную очередь |
4.3.3. Rolling Policies
| Класс | Критерий ротации |
|---|---|
TimeBasedRollingPolicy | По времени (%d{yyyy-MM-dd}) |
SizeBasedTriggeringPolicy | По размеру (maxFileSize) |
SizeAndTimeBasedRollingPolicy | По времени + размеру (%i — индекс внутри дня) |
FixedWindowRollingPolicy | Фиксированные окна (app.log, app.log.1, …) |
4.3.4. Encoders
| Тип | Описание |
|---|---|
PatternLayoutEncoder | Шаблонный вывод (аналог SimpleFormatter) |
JsonEncoder (через logback-json-classic) | Вывод в JSON (поля: timestamp, level, logger, message, thread, mdc) |
Пример JSON-шаблона:
<encoder class="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder">
<providers>
<timestamp/>
<logLevel/>
<loggerName/>
<threadName/>
<message/>
<mdc/>
<stackTrace/>
</providers>
</encoder>
4.3.5. Фильтры
| Класс | Описание |
|---|---|
ThresholdFilter | Пропускать записи ≥ уровня |
LevelFilter | Точный уровень (ACCEPT/NEUTRAL/DENY) |
EvaluatorFilter + JaninoEventEvaluator | Условия на Groovy/Janino: |
<expression>logger.contains("service") && message.contains("timeout")</expression> | |
MDCFilter | Фильтр по MDC-ключам |
4.3.6. MDC и NDLC
MDC.put("traceId", "abc123")— карта, привязанная к потоку;- В шаблоне:
%X{traceId}; NDLC.push("DB_CALL"),NDLC.pop()— стек для логической вложенности;- В шаблоне:
%x— вся цепочка через разделитель.
4.4. Log4j 2
Современный движок, несовместимый с Log4j 1.x. Конфигурация: log4j2.xml, log4j2.json, log4j2.yaml, log4j2.properties.
4.4.1. Структура log4j2.xml
<Configuration status="WARN" monitorInterval="30">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
</Console>
<RollingFile name="File" fileName="app.log"
filePattern="app.%d{yyyy-MM-dd}-%i.log.gz">
<PatternLayout>
<pattern>%d{ISO8601} [%t] %-5level %logger{40} [%X{traceId}] - %msg%n</pattern>
</PatternLayout>
<Policies>
<TimeBasedTriggeringPolicy interval="1"/>
<SizeBasedTriggeringPolicy size="100MB"/>
</Policies>
<DefaultRolloverStrategy max="30"/>
</RollingFile>
<Async name="AsyncFile">
<AppenderRef ref="File"/>
</Async>
</Appenders>
<Loggers>
<Logger name="com.example.service" level="debug" additivity="false">
<AppenderRef ref="AsyncFile"/>
</Logger>
<Root level="info">
<AppenderRef ref="Console"/>
<AppenderRef ref="AsyncFile"/>
</Root>
</Loggers>
</Configuration>
4.4.2. Особенности Log4j 2
| Фича | Описание |
|---|---|
| Async Loggers | Высокопроизводительное асинхронное логирование через Disruptor (до 10× быстрее) |
| Lookups | Динамические значения: ${env:HOME}, ${sys:user.name}, ${date:yyyy-MM}, ${docker:containerId} |
| Filters | BurstFilter, DynamicThresholdFilter, ScriptFilter (JavaScript/Groovy), StructuredDataFilter |
| Reliability | FailoverAppender, RoutingAppender (маршрутизация по условию) |
| JSON Template Layout | Готовые шаблоны: EcsLayout, GelfLayout, JsonTemplateLayout |
| JFR Integration | Автоматическая запись событий логирования в JFR-трассу |
Пример асинхронного логгера:
<AsyncLogger name="com.example" level="debug" includeLocation="true"/>
Требует com.lmax:disruptor в classpath.
4.4.3. Безопасное логирование
- Masking: через
RegexReplacementвPatternLayout:<PatternLayout>
<pattern>%m%n</pattern>
<regexReplacement regex="password=([^&]*)"
replacement="password=***"/>
</PatternLayout> - SensitiveDataFilter (Log4j 2.17+): фильтр по регулярным выражениям для маскировки.
4.5. Сравнение движков
| Критерий | JUL | Logback | Log4j 2 |
|---|---|---|---|
| Производительность | Низкая | Средняя | Высокая (Async Loggers) |
| Гибкость конфигурации | Ограниченная | Высокая | Очень высокая |
| Асинхронность | Java 19+ (AsyncHandler) | AsyncAppender | AsyncAppender, AsyncLogger |
| JSON-поддержка | Нет | Через расширения | Встроенная (JsonTemplateLayout) |
| JMX-мониторинг | Да | Да | Да |
| JFR-интеграция | Нет | Нет | Да |
| Лицензия | GPL+CE | EPL 1.0 / LGPL 2.1 | Apache 2.0 |
4.6. Рекомендации по использованию
- Используйте SLF4J как API — обеспечивает независимость от движка.
- Выбирайте Logback или Log4j 2 — JUL не подходит для production-сред.
- Включайте MDC для трассировки запросов (traceId, spanId).
- Избегайте конкатенации строк — используйте параметризованные сообщения.
- Логируйте исключения полностью —
logger.error("msg", exception), а неlogger.error("msg: " + ex.getMessage()). - Маскируйте чувствительные данные на уровне appenders.
- Ограничьте уровень логирования в production —
INFOдля root,WARN/ERRORдля внешних библиотек. - Используйте ротацию и сжатие — предотвращает заполнение диска.
- Не логируйте в
System.out/System.errнапрямую — нарушает централизованное управление.
5. Конфигурация модульной системы (JPMS)
JPMS введён в Java 9 как механизм компоновки на уровне платформы. Основные цели:
- надёжная инкапсуляция внутренних API;
- улучшенная производительность запуска и потребления памяти;
- предсказуемая сборка и развёртывание.
Модуль описывается в файле module-info.java, компилируется в module-info.class, размещается в корне JAR или директории.
5.1. Синтаксис module-info.java
[open] module <module-name> {
requires [transitive] [static] <module>;
exports <package> [to <module>, …];
opens <package> [to <module>, …];
uses <service-interface>;
provides <service-interface> with <implementation-class>;
}
5.1.1. Объявление модуля
- Именованный модуль: имеет
module-info.java, имя совпадает с именем JAR-файла (без версии и.jar) или директории. - Unnamed module: код без
module-info.java— автоматически включает все JAR из classpath, экспортирует все пакеты, требует все модули. - Automatic module: JAR без
module-info.class, но в--module-path— получает имя поAutomatic-Module-NameизMANIFEST.MFили по имени файла (без версии и расширения).
Пример:
module com.example.app {
requires java.base;
requires transitive com.example.core;
requires static org.slf4j;
exports com.example.api;
exports com.example.internal to com.example.test;
opens com.example.config;
uses com.example.spi.DatabaseDriver;
provides com.example.spi.DatabaseDriver with com.example.postgres.PostgresDriver;
}
5.1.2. Директивы
| Директива | Описание | Примечания |
|---|---|---|
requires <module> | Зависимость от модуля | Без transitive — зависимость не наследуется |
requires transitive <module> | Транзитивная зависимость | Потребители модуля автоматически require этот модуль |
requires static <module> | Опциональная зависимость (только во время компиляции) | Во время выполнения модуль может отсутствовать |
exports <package> | Публикация пакета для чтения и рефлексии | Только public классы и члены доступны |
exports <package> to <module> | Ограниченная публикация (qualified export) | Доступ только указанному модулю |
opens <package> | Разрешение рефлексивного доступа к пакету | Для всех модулей (аналог --add-opens) |
opens <package> to <module> | Ограниченный opens | Только для указанного модуля |
open module <name> | Все пакеты открыты для рефлексии | Эквивалентно opens * |
uses <service> | Объявление использования сервиса через ServiceLoader | Не требует requires модуля, содержащего интерфейс |
provides <service> with <impl> | Регистрация реализации сервиса | Класс должен реализовывать интерфейс и иметь публичный конструктор без аргументов |
🔹
exportsне даёт доступ кprivate/package-privateчерез рефлексию — только черезopens.
🔹opensне даёт доступ кprivateчленам безsetAccessible(true).
🔹provides … withтребует, чтобы реализация находилась в том же модуле.
5.2. Параметры запуска JVM для JPMS
Все параметры начинаются с --.
| Параметр | Описание | Пример |
|---|---|---|
--module-path <path> | Поиск модулей (JAR с module-info.class или автоматических) | --module-path lib:mods |
--class-path <path> | Поиск классов в unnamed module | --class-path legacy/* |
-m <module>[/<main-class>], --module <…> | Запуск модуля | --module com.example.app/com.example.Main |
--add-modules <module>,… | Явное включение модулей (даже если не требуется) | --add-modules java.xml.bind (Java 9–10, удалён в 11) |
--add-exports <source-module>/<package>=<target-module> | Динамический exports | --add-exports java.base/sun.nio.ch=ALL-UNNAMED |
--add-opens <source-module>/<package>=<target-module> | Динамический opens | --add-opens java.base/java.lang=org.mockito |
--patch-module <module>=<path> | Замена/дополнение содержимого модуля | --patch-module java.base=hotfix/ |
--limit-modules <module>,… | Ограничение набора доступных модулей | --limit-modules java.base,java.logging |
--list-modules | Вывод списка всех наблюдаемых модулей | Только в консоли |
--describe-module <module> | Описание модуля | --describe-module java.base |
| `--illegal-access=deny | permit | warn |
5.2.1. Специальные значения для --add-exports / --add-opens
| Целевой модуль | Эффект |
|---|---|
ALL-UNNAMED | Все классы в unnamed module (classpath) |
ALL-SYSTEM | Все именованные системные модули |
ALL-MODULE-PATH | Все модули из --module-path |
java.*, jdk.* | Конкретный модуль |
Пример для Mockito (требует доступа к private полям):
--add-opens java.base/java.lang=ALL-UNNAMED
--add-opens java.base/java.util=ALL-UNNAMED
5.3. Инструменты JPMS
5.3.1. jdeps — анализ зависимостей
Основное применение: выявление модульных зависимостей и непубличных API.
# Анализ JAR-файла
jdeps --module-path lib app.jar
# Проверка совместимости с модульной системой
jdeps --check MODULE_PATH --multi-release 17 app.jar
# Вывод графа зависимостей (dot-формат)
jdeps -R --generate-module-info mods app.jar
# Поиск зависимостей от internal API
jdeps --jdk-internals app.jar
Важные флаги:
-cp,--class-path— classpath (для unnamed module);-mp,--module-path— модульный путь;--print-module-deps— список требуемых модулей (для--add-modules);--generate-open-module— генерацияopen moduleдля legacy-кода.
5.3.2. jlink — сборка минимальной среды выполнения
Генерирует кастомный runtime image с заданными модулями.
jlink \
--module-path $JAVA_HOME/jmods:mods \
--add-modules com.example.app,java.logging,java.xml \
--output myruntime \
--compress 2 \
--strip-debug \
--no-header-files \
--launcher app=com.example.app/com.example.Main
Флаги:
--compress=1(ZIP),=2(ZIP + удаление отладочной инфо);--strip-debug— удаление отладочных таблиц;--launcher name=module/class— создаётbin/nameиbin/name.bat;--bind-services— включение реализацийprovides … with;--ignore-signing-information— игнорирование подписей JAR.
Результат: myruntime/ содержит bin/java, conf/, lib/, release.
5.3.3. jmod — работа с .jmod-файлами
Формат .jmod — для поставки модулей разработчикам (не для развёртывания).
# Создание .jmod
jmod create \
--class-path classes \
--main-class com.example.Main \
--module-version 1.0 \
--target-platform linux-amd64 \
app.jmod
# Просмотр содержимого
jmod list app.jmod
jmod describe app.jmod
⚠️
.jmodнельзя использовать в--module-path— только вjlink --module-path ….
5.3.4. jimage — работа с modules-образом
Внутри $JAVA_HOME/lib/modules — единый образ всех модулей JRE.
# Просмотр содержимого
jimage list $JAVA_HOME/lib/modules
# Извлечение модуля
jimage extract --dir extracted $JAVA_HOME/lib/modules java.base
# Создание кастомного образа (редко используется напрямую)
jimage create --module-path mods --output custom.jimage
5.4. Динамические модули и ModuleLayer
JPMS поддерживает создание динамических слоёв модулей во время выполнения.
ModuleFinder finder = ModuleFinder.of(Paths.get("mods"));
ModuleLayer parent = ModuleLayer.boot();
Configuration cf = parent.configuration().resolve(finder, ModuleFinder.of(), Set.of("com.example.app"));
ModuleLayer layer = parent.defineModulesWithOneLoader(cf, ClassLoader.getSystemClassLoader());
// Получение ClassLoader модуля
ClassLoader appLoader = layer.findLoader("com.example.app");
Class<?> mainClass = appLoader.loadClass("com.example.Main");
Используется в:
- плагинных системах;
- изоляции загрузчиков;
- тестовых фреймворках (JUnit 5+).
5.5. DIAGNOSTICS: анализ модульной системы
5.5.1. Через JVM
java --describe-module java.base
# → выводит requires, exports, opens, uses, provides
java --list-modules
# → все модули, наблюдаемые из boot layer
java -version --show-version
# → включает модульную информацию при `--show-version`
5.5.2. Через API
Module boot = Object.class.getModule(); // java.base
System.err.println(boot.getDescriptor().name());
// Все наблюдаемые модули
Layer.boot().modules().forEach(m ->
System.out.println(m.getName() + ": " + m.getPackages())
);
5.5.3. Ошибки и их интерпретация
| Ошибка | Причина | Решение |
|---|---|---|
module not found: X | Модуль X отсутствует в --module-path или не требуется явно | Добавить --add-modules X или включить в requires |
package Y is declared in module X, but module Z does not read it | Z не requires X, и X не exports Y в Z | Добавить requires X или --add-exports X/Y=Z |
unable to open Y in module X | Попытка рефлексии без opens | Добавить opens Y или --add-opens X/Y=Z |
provides Z with W, but W is not in this module | Реализация вне модуля | Перенести класс или использовать ServiceLoader.load(Z, layer) |
5.6. Совместимость с legacy-кодом
-
Classpath vs Module-path:
- Classpath → unnamed module → экспортирует всё, требует всё;
- Module-path → именованные/автоматические модули.
-
Split package:
Один пакет в нескольких модулях — запрещено.
Решение:--patch-module, объединение JAR, рефакторинг. -
Reflection на internal API:
--add-opens java.base/java.lang=ALL-UNNAMED— временное решение.
Рекомендуется миграция на публичные API. -
ServiceLoader в unnamed module:
ФайлMETA-INF/services/com.example.Spiв JAR на classpath работает безmodule-info.java.
6. Конфигурация сборки и развёртывания
Цель: формирование самодостаточных, безопасных и переносимых артефактов — от JAR до установщиков операционных систем.
6.1. MANIFEST.MF
Файл META-INF/MANIFEST.MF в JAR-архиве содержит метаданные. Кодировка — UTF-8 (начиная с Java 7), строки не длиннее 72 байт (перенос через пробел в начале строки).
6.1.1. Обязательные атрибуты
| Атрибут | Описание | Пример |
|---|---|---|
Manifest-Version | Версия спецификации манифеста | 1.0 |
Created-By | Инструмент создания | 17.0.12 (Eclipse Adoptium) |
6.1.2. Атрибуты запуска
| Атрибут | Описание | Примечание |
|---|---|---|
Main-Class | Полное имя класса с public static void main(String[]) | Должен быть в корне JAR или в Class-Path |
Start-Class | Используется Spring Boot — класс с @SpringBootApplication | Не стандартный, обрабатывается JarLauncher |
Launcher-Class | Для модульных JAR — модуль/класс | com.example.app/com.example.Main |
6.1.3. Атрибуты классов и зависимостей
| Атрибут | Описание | Пример |
|---|---|---|
Class-Path | Список JAR/директорий (относительно JAR) | lib/commons-lang3.jar lib/config/ |
Multi-Release | Поддержка multi-release JAR | true |
Automatic-Module-Name | Имя модуля для automatic module | org.slf4j |
⚠️
Class-Pathне поддерживает wildcard (*). Каждый JAR указывается явно.
6.1.4. Атрибуты версионирования и поставки
| Атрибут | Описание |
|---|---|
Implementation-Title, Implementation-Version, Implementation-Vendor | Идентификация реализации (доступны через Package.getImplementation*()) |
Specification-Title, Specification-Version, Specification-Vendor | Идентификация спецификации |
Sealed | Закрытие JAR: все классы должны быть подписаны и из одного источника |
Permissions | Уровень прав для Web Start (устарело) |
6.1.5. Подпись JAR (JAR Signing)
Для каждого пакета или файла — отдельная запись:
Name: com/example/
SHA-256-Digest: abc123...
Name: com/example/MyClass.class
SHA-256-Digest: def456...
Генерируется jarsigner на основе MANIFEST.MF и содержимого.
6.2. Multi-Release JAR (MRJAR)
Позволяет включать разные реализации классов для разных версий Java в один JAR.
Структура:
mylib.jar
├── META-INF/
│ └── MANIFEST.MF ← Multi-Release: true
├── com/example/Util.class ← Java 8+
└── META-INF/versions/
├── 9/com/example/Util.class ← Java 9+
├── 11/com/example/Util.class ← Java 11+
└── 17/com/example/Util.class ← Java 17+
Требования:
MANIFEST.MFсодержитMulti-Release: true;- Классы в
versions/N/должны иметь точно то же полное имя, что и в корне; - Нельзя переопределять пакеты — только классы;
- Поддерживается начиная с Java 9 (JVM выбирает версию ≤ текущей, наибольшую).
Сборка через jar:
jar --create --file mylib.jar \
--main-class com.example.Main \
-C classes8 . \
--release 9 -C classes9 . \
--release 11 -C classes11 . \
--release 17 -C classes17 .
Проверка:
jar --describe-module --file mylib.jar
# или
unzip -l mylib.jar | grep versions
6.3. Sealed JAR
Запрещает загрузку классов из того же пакета, но из другого JAR или источника.
В MANIFEST.MF:
Name: com/example/internal/
Sealed: true
Эффект:
new URLClassLoader(new URL[]{other.jar}).loadClass("com.example.internal.X") → SecurityException.
Используется для защиты внутренних API.
6.4. jar — утилита управления архивами
6.4.1. Основные команды
| Команда | Описание |
|---|---|
jar --create --file app.jar -C classes . | Создание JAR из директории |
jar --update --file app.jar -C config application.properties | Добавление файла |
jar --extract --file app.jar | Распаковка |
jar --list --file app.jar | Список содержимого |
jar --describe-module --file app.jar | Анализ модульности |
jar --print-module-descriptor --file app.jar | Вывод module-info |
6.4.2. Модульные JAR
jar --create --file app.jar \
--main-class com.example.Main \
-C build/classes/module-info.class \
-C build/classes .
Требования:
module-info.classв корне;- имя JAR совпадает с именем модуля (рекомендуется).
6.5. jpackage — сборка native-установщиков
Генерирует пакеты для ОС: .deb, .rpm, .msi, .pkg, .app, app-image.
6.5.1. Режимы
| Режим | Описание |
|---|---|
--type app-image | Самодостаточная директория (без установщика) |
--type deb/rpm/msi/pkg/app-image | Установщик или образ |
6.5.2. Основные параметры
| Параметр | Описание | Пример |
|---|---|---|
--input <dir> | Директория с JAR и зависимостями | --input libs |
--main-jar <jar> | Главный JAR | --main-jar app.jar |
--main-class <class> | Класс main (если не в MANIFEST.MF) | --main-class com.example.Main |
--name <name> | Имя приложения | --name MyApp |
--app-version <ver> | Версия | --app-version 1.2.0 |
--vendor <name> | Поставщик | --vendor "Example Inc." |
--description <text> | Описание | --description "My Java App" |
--icon <file> | Иконка (.ico, .png, .icns) | --icon app.ico |
--linux-shortcut, --win-shortcut, --mac-package-identifier | ОС-специфичные опции |
6.5.3. Сценарий: сборка .deb с runtime
# 1. Сборка runtime через jlink
jlink \
--module-path $JAVA_HOME/jmods:libs \
--add-modules com.example.app,java.logging \
--output runtime \
--strip-debug \
--compress 2
# 2. Подготовка input: JAR + runtime
mkdir -p package/{app,bin}
cp app.jar package/app/
cp -r runtime/* package/bin/
# 3. Сборка DEB
jpackage \
--type deb \
--input package/app \
--main-jar app.jar \
--runtime-image package/bin \
--name myapp \
--app-version 1.0.0 \
--vendor "Example" \
--description "My App" \
--linux-shortcut
Результат: myapp_1.0.0-1_amd64.deb, устанавливаемый через dpkg -i.
⚠️
jpackageтребует установленных системных утилит:
- Linux:
dpkg,rpmbuild;- Windows: WiX Toolset (3.11+);
- macOS:
pkgbuild,productbuild.
6.6. jlink — расширенные сценарии
6.6.1. Оптимизация образа
| Флаг | Действие |
|---|---|
--strip-debug | Удаление отладочной информации (line number tables, local variables) |
--compress=2 | Сжатие class-файлов (ZIP + stripping) |
--no-header-files | Удаление include/ (заголовки JNI) |
--no-man-pages | Удаление man-страниц |
--strip-native-commands | Удаление jcmd, jinfo, jmap и др. (остаётся только java) |
| `--endian little | big` |
| `--vm server | client |
6.6.2. Кастомизация release-файла
Файл release в корне образа содержит:
JAVA_VERSION="17.0.12"
MODULES="java.base java.logging com.example.app"
SOURCE="…"
IMPLEMENTOR="Eclipse Adoptium"
Можно дополнить через --release-info-file custom.properties.
6.7. jdeps — расширенный анализ
6.7.1. Генерация module-info.java
jdeps --generate-module-info mods app.jar
# → mods/com.example.app/module-info.java
Автоматически определяет:
requires— по использованию классов;exports— поpublicклассам, используемым извне;opens— если обнаружено использование рефлексии.
6.7.2. Выявление недостающих зависимостей
jdeps --suggest-missing-deps app.jar
# → [NOT FOUND] requires java.xml.bind (inaccessible)
6.7.3. Проверка multi-release-совместимости
jdeps --multi-release 17 --class-path libs app.jar
6.8. Подпись JAR: jarsigner и keytool
6.8.1. Генерация ключей
# 1. Создание keystore
keytool -genkeypair \
-alias mykey \
-keyalg RSA \
-keysize 4096 \
-sigalg SHA384withRSA \
-dname "CN=Timur Tagirov, O=IT Universe, C=RU" \
-validity 3650 \
-keystore keystore.jks \
-storepass changeit \
-keypass changeit
6.8.2. Подпись
jarsigner \
-keystore keystore.jks \
-storepass changeit \
-keypass changeit \
-sigalg SHA384withRSA \
-digestalg SHA-384 \
-tsa http://timestamp.digicert.com \
app.jar mykey
Флаги:
-tsa— сервер временных меток (требуется для валидности после истечения срока ключа);-verbose— детальный вывод;-certs— включить цепочку сертификатов.
6.8.3. Проверка подписи
jarsigner -verify -verbose -certs app.jar
Вывод включает:
- действительность подписи;
- цепочку сертификатов;
- наличие временной метки;
- соответствие политики (
jdk.jar.disabledAlgorithms).
6.9. Рекомендации по развёртыванию
- Используйте
jlink + jpackageдля production-дистрибутивов — уменьшает размер, исключает ненужные модули. - Подписывайте JAR, если требуется проверка целостности (например, в enterprise-средах).
- Избегайте
Class-Pathс абсолютными путями — нарушает переносимость. - Для библиотек — указывайте
Automatic-Module-NameвMANIFEST.MF, даже если нетmodule-info.java. - Multi-release JAR — только при необходимости — усложняет сборку и отладку.
- Sealed JAR — для внутренних SDK, где критична изоляция пакетов.
7. Конфигурация инструментов JDK
Инструменты JDK делятся на:
- Сборочные:
javac,javadoc,jar,jmod; - Диагностические:
jps,jstat,jmap,jstack,jinfo,jcmd; - Интерактивные:
jshell; - Профилировочные:
jfr.
Все они поставляются в $JAVA_HOME/bin/. Начиная с Java 11, отдельный JRE удалён — все инструменты входят в стандартный JDK.
7.1. javac — компилятор Java
7.1.1. Основные параметры
| Параметр | Описание | Пример |
|---|---|---|
-d <dir> | Директория вывода .class | -d build/classes |
-s <dir> | Директория вывода сгенерированных исходников (например, @Generated) | -s src/generated |
-sourcepath <path> | Поиск исходников зависимостей | -sourcepath src/main:src/lib |
-classpath <path>, -cp <path> | Classpath для разрешения ссылок | -cp lib/* |
--module-path <path>, -p <path> | Модульный путь | --module-path mods |
--module-source-path <path> | Исходники модулей (структура modA/src, modB/src) | --module-source-path 'modules/*/src' |
7.1.2. Целевая совместимость
| Параметр | Описание |
|---|---|
--release <N> | Компиляция для версии N (от 7 до текущей) |
-source <N>, -target <N> | Устаревшие (до Java 9); --release предпочтительнее — гарантирует корректные bootstrap-классы |
--enable-preview | Использование preview-фич текущей версии |
🔹
--release 11эквивалентно:
-source 11 -target 11 -bootclasspath $JAVA_HOME/jmods/java.base.jar(внутренне).
7.1.3. Предупреждения и линтинг (-Xlint)
| Флаг | Описание |
|---|---|
-Xlint:all | Все предупреждения |
-Xlint:none | Отключить все |
-Xlint:deprecation | Использование @Deprecated |
-Xlint:unchecked | Небезопасные операции с generic’ами |
-Xlint:varargs | Проблемы с T... и Object[] |
-Xlint:cast | Избыточные приведения типов |
-Xlint:fallthrough | Отсутствие break в switch |
-Xlint:finally | return в finally |
-Xlint:path | Недостижимые пути |
-Xlint:serial | Отсутствие serialVersionUID в Serializable |
-Xlint:module | Проблемы модульной системы |
-Werror | Любое предупреждение → ошибка |
Пример:
javac -Xlint:unchecked,deprecation -Werror -d bin src/*.java
7.1.4. Аннотации
| Параметр | Описание |
|---|---|
-processor <class> | Явное указание annotation processor’а |
-processorpath <path> | Classpath для процессоров |
-s <dir> | Куда писать сгенерированные исходники |
-implicit:none | Не компилировать классы, не указанные явно |
7.2. javadoc — генерация документации
7.2.1. Стандартные теги
| Тег | Контекст | Описание |
|---|---|---|
@param <name> | Метод/конструктор | Описание параметра |
@return | Метод | Возвращаемое значение |
@throws <Exception> | Метод | Исключение и условие его возникновения |
@see <ref> | Любой | Перекрёстная ссылка |
@link <ref> | Внутри описания | Инлайновая ссылка |
@since <version> | Любой | Версия, в которой появилось |
@deprecated | Любой | Устаревшее API |
@implSpec | Интерфейс/абстрактный метод | Требования к реализации |
@implNote | Любой | Замечание для реализатора |
7.2.2. Параметры генерации
| Параметр | Описание |
|---|---|
-d <dir> | Выходная директория |
-sourcepath <path> | Поиск исходников |
--module-path <path> | Модульный путь |
--module-source-path <path> | Исходники модулей |
-public, -protected, -package, -private | Уровень видимости |
-author, -version | Включать @author, @version |
-noindex | Не генерировать индекс |
-notree | Без иерархии классов |
-nohelp | Без ссылки на help |
-link <url> | Внешние javadoc (например, JDK) |
-stylesheetfile <css> | Кастомный CSS |
7.2.3. Модульные отчёты
javadoc \
--module-path mods \
--module com.example.app \
-d docs \
-author -version
Генерирует:
module-summary.html— обзор модуля;package-summary.html— по пакетам;- Поддержка
module-info.javaв навигации.
7.2.4. HTML5 и безопасность
Начиная с Java 17, javadoc генерирует только HTML5.
Поддержка --allow-script-in-comments удалена — скрипты в комментариях игнорируются.
7.3. jshell — интерактивный REPL
7.3.1. Запуск и режимы
| Команда | Эффект |
|---|---|
jshell | Интерактивный режим |
jshell script.jsh | Выполнение скрипта |
jshell --execution-timeout 30s | Таймаут выражения |
jshell -q | Тихий режим (без приветствия) |
jshell --startup DEFAULT, --startup <file> | Загрузка стартовых команд |
7.3.2. Встроенные команды (начинаются с /)
| Команда | Описание |
|---|---|
/help | Справка |
/list | Список всех введённых фрагментов |
/list <id> | Конкретный фрагмент |
/edit <id> | Редактирование в external editor (требует $JSHELLEDITOR или --editor) |
/drop <id> | Удаление фрагмента |
/save filename | Сохранение сессии |
/open filename | Загрузка сессии |
/env | Текущее окружение (classpath, modules, feedback) |
| `/set feedback verbose | concise |
/exit | Выход |
7.3.3. Особенности
- Поддержка
var,record,switchexpressions, текстовых блоков; - Автодополнение (
Tab); - История (
↑,↓); - Мультистрочные выражения (ввод до
;); - Возможность импорта пакетов:
/import java.util.*.
Пример:
jshell> /set feedback verbose
jshell> class Point { int x, y; Point(int x, int y) { this.x = x; this.y = y; } }
| created class Point
jshell> new Point(1, 2)
| $1 ==> Point@1a2b3c
| x: 1
| y: 2
7.4. jcmd — универсальная управляющая утилита
Выполняет команды в работающей JVM. Единственный инструмент, поддерживающий все диагностические операции в новых версиях Java (остальные (jstack, jmap) — устаревшие, реализованы через jcmd).
7.4.1. Общая структура
jcmd [<pid>|<main-class>|0] <command> [arguments]
0 — все локальные JVM.
7.4.2. Основные команды
| Команда | Описание |
|---|---|
VM.version | Версия JVM |
VM.command_line | Аргументы запуска |
VM.flags [-all] | Все флаги JVM |
VM.set_flag <name> <value> | Изменение non-manageable флага (только если manageable = true) |
GC.run | Принудительный GC (эквивалент System.gc()) |
GC.run_finalization | Запуск finalization |
Thread.print [-l] | Стеки потоков (аналог jstack) |
VM.class_hierarchy [-i] [-v] | Иерархия классов (требует UnlockDiagnosticVMOptions) |
VM.classloader_stats | Статистика загрузчиков |
VM.stringtable [-verbose] | Интроспекция string pool |
VM.symboltable | Таблица символов |
PerfCounter.print | Счётчики производительности |
JFR.start [settings=…] [filename=…] [duration=…] | Запуск Flight Recorder |
JFR.stop [name=…] [filename=…] | Остановка и сохранение |
JFR.check | Состояние записей |
ManagementAgent.start [port=…] | Включение JMX (если не был включён при старте) |
7.4.3. Примеры
# Список всех JVM
jcmd -l
# Дамп потоков
jcmd 12345 Thread.print
# Запуск JFR на 60 секунд
jcmd 12345 JFR.start name=MyRecording settings=profile duration=60s filename=rec.jfr
# Изменение MaxGCPauseMillis в runtime (если manageable)
jcmd 12345 VM.set_flag MaxGCPauseMillis 200
✅
jcmd— предпочтительный инструмент для production-диагностики.
7.5. jps — список Java-процессов
| Флаг | Описание |
|---|---|
jps | PID + короткое имя main-class/JAR |
jps -l | Полный путь к main-class или JAR |
jps -v | Аргументы JVM |
jps -m | Аргументы main-метода |
jps -q | Только PID |
Пример:
$ jps -lv
12345 /opt/app/app.jar -Xmx2g -Dfile.encoding=UTF-8
12346 org.apache.catalina.startup.Bootstrap start
7.6. jstat — статистика GC и JIT
| Команда | Описание |
|---|---|
jstat -gc <pid> [interval] [count] | Сборка мусора (Eden, Survivor, Old, Metaspace) |
jstat -gccapacity <pid> | Ёмкости поколений |
jstat -gcutil <pid> | % использования поколений |
jstat -compiler <pid> | Статистика JIT (методы, время компиляции) |
jstat -printcompilation <pid> | Последние скомпилированные методы |
Пример:
jstat -gcutil 12345 1s 5
S0 S1 E O M CCS YGC YGCT FGC FGCT GCT
0.00 98.45 76.32 45.12 95.34 92.11 123 2.345 5 1.234 3.579
Где:
S0/S1 — Survivor 0/1,
E — Eden,
O — Old,
M — Metaspace,
CCS — Compressed Class Space,
YGC/YGCT — Young GC count/time,
FGC/FGCT — Full GC count/time,
GCT — Total GC time.
7.7. jmap — анализ памяти
| Команда | Описание |
|---|---|
jmap -heap <pid> | Сводка по heap (поколения, GC, capacity) |
jmap -histo <pid> | Гистограмма классов (экземпляры, байты) |
jmap -histo:live <pid> | Только живые объекты (запускает GC) |
jmap -dump:live,format=b,file=heap.hprof <pid> | Heap-дамп в HPROF-формате |
⚠️
jmapприостанавливает JVM на время операции. В production используйтеjcmd <pid> GC.run_finalization+jcmd <pid> VM.class_histogram, или JFR.
7.8. jstack — дамп стеков потоков
| Команда | Описание |
|---|---|
jstack <pid> | Стеки всех потоков |
jstack -l <pid> | + информация о мониторах и owns |
jstack -F <pid> | Принудительный дамп (если JVM не отвечает) |
Формат вывода:
"main" #1 prio=5 os_prio=0 cpu=123.45ms elapsed=10.00s tid=0x00007f0000000000 nid=0x1234 runnable
java.lang.Thread.State: RUNNABLE
at java.util.HashMap.hash(HashMap.java:339)
at java.util.HashMap.put(HashMap.java:612)
at com.example.Main.main(Main.java:10)
🔹 В Java 8–16
jstackработает напрямую; в Java 17+ — обёртка надjcmd <pid> Thread.print.
7.9. jinfo — конфигурация JVM
| Команда | Описание |
|---|---|
jinfo <pid> | Все системные свойства и флаги |
jinfo -sysprops <pid> | Только System.getProperty |
jinfo -flags <pid> | Только -XX флаги |
jinfo -flag <name> <pid> | Значение конкретного флага |
jinfo -flag +<name> <pid> | Включить boolean-флаг (если manageable) |
⚠️ Большинство флагов — non-manageable и не могут быть изменены в runtime.
7.10. jfr — работа с Flight Recorder
| Команда | Описание |
|---|---|
jfr status <pid> | Активные записи |
jfr start <pid> [name=…] [settings=…] [duration=…] [filename=…] | Запуск записи |
jfr stop <pid> [name=…] [filename=…] | Остановка и сохранение |
jfr dump <pid> [name=…] [filename=…] | Дамп текущего буфера без остановки |
jfr print <file.jfr> | Текстовый вывод событий |
jfr metadata <file.jfr> | Описание типов событий |
jfr extract <file.jfr> --events <type> | Извлечение подмножества событий |
Форматы settings:
default— минимальная нагрузка;profile— полная (методы, allocation, TLAB, monitor, socket);flightrecorder— кастомный (.jfc-файл).
Пример кастомного .jfc:
<configuration version="2.0">
<event name="jdk.CPULoad">
<setting name="enabled">true</setting>
<setting name="period">1 s</setting>
</event>
</configuration>
Загрузка:
jfr start 12345 settings=cpu.jfc filename=cpu.jfr
8. Spring Boot — внешняя конфигурация
Spring Boot предоставляет унифицированную модель загрузки конфигурации из множества источников, с приоритезацией, профилированием, типобезопасным связыванием и поддержкой внешних систем.
Все конфигурационные свойства доступны через Environment и @ConfigurationProperties.
8.1. Иерархия источников конфигурации
Spring Boot загружает свойства в строго определённом порядке, где более поздние источники переопределяют более ранние:
| Приоритет | Источник | Описание |
|---|---|---|
| 1 | @TestPropertySource | Аннотация на тестах |
| 2 | Аргументы @SpringBootTest(properties = …) | В тестах |
| 3 | properties атрибут @SpringBootTest, @WebMvcTest и др. | |
| 4 | Аргументы командной строки (--name=value) | Через SpringApplication.run(args) |
| 5 | Свойства из SPRING_APPLICATION_JSON (переменная окружения или системное свойство) | {"app.port":8081} → app.port=8081 |
| 6 | ServletConfig init-параметры | В веб-приложениях |
| 7 | ServletContext init-параметры | |
| 8 | JNDI-атрибуты (java:comp/env/) | |
| 9 | System.getProperties() | Системные свойства JVM (-D…) |
| 10 | Системные переменные окружения | APP_PORT=8081 |
| 11 | RandomValuePropertySource | random.int, random.uuid |
| 12 | Профильные application-{profile}.properties из упакованного JAR | |
| 13 | application.properties из упакованного JAR (classpath:/) | |
| 14 | Профильные application-{profile}.properties из config/ в текущей директории | ./config/application-prod.properties |
| 15 | application.properties из config/ в текущей директории | ./config/application.properties |
| 16 | Профильные application-{profile}.properties в текущей директории | ./application-prod.properties |
| 17 | application.properties в текущей директории | ./application.properties |
| 18 | @PropertySource на @Configuration-классах | Загружается до application.properties, но после системных источников 1–11 — важное исключение из порядка |
| 19 | Конфиги, загруженные через spring.config.import | Выполняются в порядке объявления, после application.properties, но до @PropertySource с @DependsOn |
✅ Актуально для Spring Boot 2.4+. До 2.4 порядок
@PropertySourceбыл выше.
8.2. Синтаксис application.properties и application.yml
8.2.1. application.properties
# Простые значения
server.port=8080
app.name=MyApp
app.version=1.2.0
# Списки
app.features=auth,logging,metrics
app.ports=8080,8081,8082
# Вложенные объекты (точечная нотация)
app.datasource.url=jdbc:postgresql://localhost:5432/mydb
app.datasource.username=admin
app.datasource.password=secret
app.datasource.pool.size=10
app.datasource.pool.timeout=30s
# Случайные значения
app.id=${random.uuid}
app.port=${random.int[8000,9000]}
8.2.2. application.yml
server:
port: 8080
app:
name: MyApp
version: 1.2.0
features:
- auth
- logging
- metrics
ports:
- 8080
- 8081
- 8082
datasource:
url: jdbc:postgresql://localhost:5432/mydb
username: admin
password: secret
pool:
size: 10
timeout: 30s
id: ${random.uuid}
port: ${random.int[8000,9000]}
🔹 Spring Boot использует SnakeYAML для парсинга.
🔹 Поддерживаются!!int,!!binary, но не рекомендуются — снижают переносимость.
8.3. Профили (spring.profiles.active)
8.3.1. Активация
| Способ | Пример |
|---|---|
| Системное свойство | -Dspring.profiles.active=prod,metrics |
| Переменная окружения | SPRING_PROFILES_ACTIVE=prod,metrics |
application.properties | spring.profiles.active=dev |
application.yml | spring: profiles: active: dev |
| Программно | SpringApplication.setAdditionalProfiles("test") |
8.3.2. Условная загрузка
# application.yml
spring:
config:
activate:
on-profile: dev
logging:
level:
com.example: DEBUG
---
spring:
config:
activate:
on-profile: prod
logging:
level:
com.example: WARN
server:
shutdown: graceful
🔹
---— разделитель документов в YAML.
🔹 Вproperties— отдельные файлы:application-dev.properties,application-prod.properties.
8.3.3. Включение профилей из кода
@Profile("integration-test")
@Configuration
public class TestDataSourceConfig { … }
8.4. spring.config.import — импорт внешних конфигураций
Введён в Spring Boot 2.4 для замены spring.config.location (устаревшего). Поддерживает:
| Префикс | Источник | Пример |
|---|---|---|
optional:classpath: | JAR/classpath (необязательный) | optional:classpath:config/external.properties |
classpath: | JAR/classpath (обязательный) | classpath:secrets.properties |
optional:file: | Файл (необязательный) | optional:file:/etc/app/config.properties |
file: | Файл (обязательный) | file:./local.conf |
configtree: | Дерево файлов как свойства | configtree:/etc/secrets/ |
vault: | HashiCorp Vault (через Spring Cloud) | vault://secret/data/myapp |
consul: | Consul KV (Spring Cloud) | consul:myapp/config |
zookeeper: | ZooKeeper (Spring Cloud) | zookeeper:/config/myapp |
8.4.1. configtree — безопасное хранение секретов
Структура:
/etc/secrets/
├── db.username
├── db.password
└── api.token
Содержимое файлов — plain text:
# /etc/secrets/db.username
admin
В application.properties:
spring.config.import=optional:configtree:/etc/secrets/
Результат:
db.username=admin, db.password=secret, api.token=abc123.
Преимущества:
- файлы могут иметь
chmod 600; - не попадают в логи при
--debug; - не требуют шифрования внутри.
8.5. @ConfigurationProperties — типобезопасная конфигурация
8.5.1. Объявление
@ConfigurationProperties(prefix = "app.datasource")
@ConstructorBinding // immutable, требует @EnableConfigurationProperties или @ConfigurationPropertiesScan
public record DataSourceProperties(
String url,
String username,
String password,
Pool pool
) {}
public record Pool(int size, Duration timeout) {}
8.5.2. Активация
@SpringBootApplication
@EnableConfigurationProperties(DataSourceProperties.class)
public class Application { … }
Или глобально:
@ConfigurationPropertiesScan("com.example.config")
public class Config { … }
8.5.3. Валидация
@ConfigurationProperties(prefix = "app.datasource")
@Validated
public record DataSourceProperties(
@NotBlank String url,
@NotBlank String username,
@NotBlank String password,
@Valid Pool pool
) {}
public record Pool(
@Min(1) @Max(100) int size,
@NotNull @Positive Duration timeout
) {}
Ошибка приведёт к BindValidationException при старте.
8.5.4. Конвертация типов
Поддерживаются:
Duration←"30s","5m",PT30S;DataSize←"10MB","2GiB";Charset←"UTF-8";Resource←"classpath:app.sql","file:/tmp/data.txt";List<T>,Set<T>,Map<String, T>;- Кастомные
Converter<T, R>и@ConfigurationPropertiesBinding.
Пример конвертера:
@Component
@ConfigurationPropertiesBinding
public class PasswordConverter implements Converter<String, EncryptedPassword> {
public EncryptedPassword convert(String source) {
return new EncryptedPassword(AES.encrypt(source, key));
}
}
8.6. @Value vs @ConfigurationProperties
| Критерий | @Value | @ConfigurationProperties |
|---|---|---|
| Типизация | Строгая привязка к типу, но без вложенных объектов | Полная поддержка вложенных структур |
| Валидация | Только через SpEL (#{…}), без @Valid | Поддержка Bean Validation |
| Метаданные | Нет | Генерирует META-INF/spring-configuration-metadata.json для IDE |
| Производительность | Разбор SpEL при каждом доступе | Однократное связывание при старте |
| Иммутабельность | Только через final + конструктор | Поддержка @ConstructorBinding и record’ов |
| Тестирование | Требует @TestPropertySource | Легко заменяется моком |
Рекомендация:
— @ConfigurationProperties — для групп связанных свойств (DAO, клиенты, настройки модуля);
— @Value — для единичных значений (@Value("${app.id}") String id).
8.7. Интеграция с внешними системами
8.7.1. Spring Cloud Config Server
bootstrap.yml (загружается до application.*):
spring:
application:
name: myapp
cloud:
config:
uri: http://config-server:8888
username: client
password: secret
fail-fast: true
Конфиг на сервере: myapp-prod.yml:
app:
datasource:
url: jdbc:postgresql://prod-db:5432/mydb
8.7.2. HashiCorp Vault
spring.config.import=vault://secret/data/myapp
spring.cloud.vault:
host: vault.example.com
port: 8200
scheme: https
authentication: TOKEN
token: s.xxxxx
Данные из secret/data/myapp → app.*.
8.7.3. AWS Secrets Manager
Через spring.config.import=configtree:/mnt/secrets/, где /mnt/secrets/ — volume с секретами, примонтированными как файлы (ECS/EKS sidecar-паттерн).
8.8. Расширение конфигурационного конвейера
8.8.1. EnvironmentPostProcessor
Выполняется до обработки application.properties.
public class CustomEnvPostProcessor implements EnvironmentPostProcessor {
@Override
public void postProcessEnvironment(ConfigurableEnvironment env, SpringApplication app) {
Map<String, Object> map = new HashMap<>();
map.put("app.runtime", "kubernetes");
env.getPropertySources().addFirst(new MapPropertySource("custom", map));
}
}
Регистрация в META-INF/spring.factories:
org.springframework.boot.env.EnvironmentPostProcessor=\
com.example.CustomEnvPostProcessor
8.8.2. ConfigDataLocationResolver + ConfigDataLoader
Для кастомных префиксов (например, myconf:).
-
Реализация
ConfigDataLocationResolver<MyConfigDataResource>:@Order(HIGHEST_PRECEDENCE)
public class MyConfigLocationResolver implements ConfigDataLocationResolver<MyConfigDataResource> {
@Override
public boolean isResolvable(ConfigDataLocationResolverContext context, ConfigDataLocation location) {
return location.hasPrefix("myconf:");
}
@Override
public List<MyConfigDataResource> resolve(ConfigDataLocationResolverContext context, ConfigDataLocation location) {
return List.of(new MyConfigDataResource(location.getNonPrefixedValue()));
}
} -
Реализация
ConfigDataLoader<MyConfigDataResource>:public class MyConfigDataLoader implements ConfigDataLoader<MyConfigDataResource> {
@Override
public ConfigData load(ConfigDataLoaderContext context, MyConfigDataResource resource) {
Map<String, Object> props = fetchFromCustomSource(resource.getLocation());
return new ConfigData(PropertySource.of("myconf", props));
}
} -
Регистрация в
spring.factories:org.springframework.boot.context.config.ConfigDataLocationResolver=\
com.example.MyConfigLocationResolver
org.springframework.boot.context.config.ConfigDataLoader=\
com.example.MyConfigDataLoader
8.9. Безопасность конфигурации
8.9.1. Шифрование значений
Jasypt (неофициально, сторонняя библиотека):
app.datasource.password=ENC(G5xJ5s1W3QzK8c9Y1U4aB2vC4nM6lO0p)
Spring Cloud Vault / AWS KMS / Azure Key Vault — предпочтительные production-решения.
8.9.2. Защита от утечек
- Запрет логирования
@ConfigurationPropertiesс@Sensitive(кастомная аннотация +PropertySourcesDeducer); - Использование
configtreeвместоapplication.propertiesдля секретов; spring.main.lazy-initialization=true— уменьшает риск преждевременного связывания.
9. Jakarta EE / MicroProfile Config
MicroProfile Config — стандарт конфигурации для микросервисов, часть спецификации MicroProfile. Принят в Jakarta EE как основа для jakarta.config (предварительно — MP Config 3.0+).
Реализации: SmallRye Config (Quarkus, WildFly), Helidon Config, Open Liberty, Payara Micro.
9.1. Основные принципы
- Декларативность: конфигурация через
@ConfigProperty,@Inject Config; - Иерархия источников: от высокоуровневых (переменные окружения) к низкоуровневым (файлы);
- Типобезопасность: автоматическая конвертация в
int,Duration,List,Map; - Динамичность: поддержка обновления конфигурации без перезапуска (в реализациях);
- Расширяемость: кастомные
ConfigSource,Converter.
9.2. Источники конфигурации и приоритеты
Приоритет определяется целым числом (ordinal). Чем больше ordinal — тем выше приоритет.
| Источник | ordinal по умолчанию | Описание |
|---|---|---|
Programmatically added ConfigSource | Указывается явно | Наивысший приоритет при ordinal > 1000 |
System properties (-Dkey=value) | 400 | System.getProperty() |
| Environment variables | 300 | System.getenv() |
.env файл в корне проекта | 295 | Поддерживается SmallRye, Helidon |
microprofile-config.properties в рабочей директории | 250 | ./microprofile-config.properties |
META-INF/microprofile-config.properties в JAR | 100 | Упакованный в артефакт |
Custom ConfigSource без ordinal | 100 | По умолчанию |
🔹 Переменные окружения транслируются в свойства по правилу:
APP_DATASOURCE_URL→app.datasource.url(регистронезависимо,_→.,__→_).
Пример:
export APP_DATASOURCE__URL=jdbc:postgresql://prod:5432/mydb
# → app.datasource.url=jdbc:postgresql://prod:5432/mydb
9.3. Формат microprofile-config.properties
Расположение:
META-INF/microprofile-config.properties— в JAR;microprofile-config.properties— в текущей директории (для dev-сред).
Синтаксис:
# Простые значения
app.name=MyService
app.version=1.2.0
# Списки
app.ports=8080,8081,8082
app.features=auth;logging;metrics # разделитель можно задать через Config API
# Временные величины
app.timeout=30s
app.delay=5m
# Объём
app.cache.size=100MB
# Секреты (не шифруются по умолчанию)
app.datasource.password=secret
Поддерживаются те же типы, что и в Spring Boot: String, int/Integer, long/Long, boolean/Boolean, Duration, LocalDateTime, URL, URI, Charset, Class, List<T>, Set<T>, Map<String, T>.
9.4. Программное API: Config, ConfigProvider
9.4.1. Получение Config
Config config = ConfigProvider.getConfig();
// или через CDI
@Inject
Config config;
9.4.2. Чтение значений
// Обязательное значение
String name = config.getValue("app.name", String.class);
// Опциональное значение
Optional<Integer> port = config.getOptionalValue("app.port", Integer.class);
// Со значениями по умолчанию
int timeout = config.getValue("app.timeout", int.class, () -> 30);
// Списки
List<Integer> ports = config.getValues("app.ports", Integer.class);
// Map (ключ=значение, по строковому шаблону)
Map<String, String> props = config.getValues("app.datasource", String.class, String.class);
// → app.datasource.url, app.datasource.username → {url=..., username=...}
9.4.3. Интроспекция источников
config.getConfigSources().forEach(source -> {
System.out.println(source.getName() + " (ordinal=" + source.getOrdinal() + ")");
});
9.5. CDI-инъекция: @ConfigProperty
9.5.1. Базовое использование
@ApplicationScoped
public class Service {
@Inject
@ConfigProperty(name = "app.name")
String appName;
@Inject
@ConfigProperty(name = "app.ports")
List<Integer> ports;
@Inject
@ConfigProperty(name = "app.enabled", defaultValue = "true")
boolean enabled;
@Inject
@ConfigProperty(name = "app.timeout")
Duration timeout; // "30s" → Duration.ofSeconds(30)
}
9.5.2. Обработка отсутствующих значений
- Без
defaultValue—DeploymentExceptionпри старте, если свойство не найдено; - С
defaultValue— используется значение по умолчанию; Optional<T>— безопасное чтение:@Inject
@ConfigProperty(name = "app.optional.token")
Optional<String> token;
🔹
@ConfigPropertyработает только в CDI-биньках (@ApplicationScoped,@RequestScopedи др.).
9.6. Типобезопасная конфигурация: @ConfigProperties (MicroProfile 3.0+)
Аналог @ConfigurationProperties в Spring Boot.
9.6.1. Объявление
@ConfigProperties(prefix = "app.datasource")
public interface DataSourceConfig {
String url();
String username();
String password();
PoolConfig pool();
@ConfigProperties(prefix = "pool")
interface PoolConfig {
int size();
Duration timeout();
}
}
Или классом:
@ConfigProperties(prefix = "app.datasource")
public class DataSourceConfig {
private String url;
private String username;
private String password;
private PoolConfig pool;
// геттеры/сеттеры или record-конструктор
}
9.6.2. Инъекция
@Inject
DataSourceConfig config;
// Использование
DataSource ds = new DataSource(config.url(), config.username(), config.password());
🔹 В SmallRye Config поддерживается
@ConfigMapping(альтернативное имя для@ConfigProperties).
🔹 В Quarkus —@ConfigMappingс поддержкой@WithDefault,@WithParentName,@WithName.
9.7. Расширение: кастомные ConfigSource
9.7.1. Реализация
public class DatabaseConfigSource implements ConfigSource {
private final Map<String, String> properties = loadFromDatabase();
@Override
public int getOrdinal() {
return 500; // выше system props
}
@Override
public Set<String> getPropertyNames() {
return properties.keySet();
}
@Override
public String getValue(String propertyName) {
return properties.get(propertyName);
}
@Override
public String getName() {
return "DatabaseConfigSource";
}
}
9.7.2. Регистрация
Через META-INF/services/org.eclipse.microprofile.config.spi.ConfigSource:
com.example.DatabaseConfigSource
Или программно:
Config config = ConfigProviderResolver.instance()
.getBuilder()
.withSources(new DatabaseConfigSource())
.build();
ConfigProviderResolver.instance().registerConfig(config, getClass().getClassLoader());
⚠️ При программной регистрации — только для текущего
ClassLoader.
9.8. Кастомные Converter
9.8.1. Реализация
@Priority(100) // выше встроенных
public class PasswordConverter implements Converter<String> {
@Override
public String convert(String value) {
return AES.decrypt(value, getKey());
}
}
9.8.2. Регистрация
Через META-INF/services/org.eclipse.microprofile.config.spi.Converter:
com.example.PasswordConverter
Или для конкретного типа:
public class DurationConverter implements Converter<Duration> {
@Override
public Duration convert(String value) {
return Duration.parse("PT" + value.toUpperCase());
}
}
→ применяется при config.getValue("key", Duration.class).
9.9. Динамическая конфигурация и события
9.9.1. Поддержка в runtime’ах
- Quarkus:
@ConfigProperty(reactive = true)+@Observes ConfigValueChangeEvent; - SmallRye Config:
@Inject @ConfigProperty ConfigValue+ConfigValueObserver; - Helidon:
Config.onChange(…).
9.9.2. Пример (SmallRye)
@ApplicationScoped
public class ConfigObserver {
@Inject
@ConfigProperty(name = "app.feature.toggle")
ConfigValue toggle;
void onConfigChange(@Observes ConfigValueChangeEvent event) {
if ("app.feature.toggle".equals(event.getKey())) {
System.out.println("Feature toggle changed to: " + event.getValue());
}
}
}
🔹 Требует
mp.configвpom.xmlи активной поддержки в runtime.
9.10. Интеграции с runtime’ами
| Runtime | Поддержка | Особенности |
|---|---|---|
| Quarkus | Полная (SmallRye Config) | application.properties, @ConfigMapping, dev-services, config hot reload в dev mode |
| Helidon | Встроенная | application.yaml, config profiles, programmatic builder |
| Open Liberty | MP Config 3.0+ | server.xml + microprofile-config.properties, dynamic updates |
| WildFly | SmallRye Config | standalone.xml + META-INF/microprofile-config.properties |
| Payara Micro | MP Config | Поддержка configsource в payara-micro.properties |
9.10.1. Quarkus: расширенные возможности
- Profile-specific properties:
%prod.app.url=…; - Config profiles:
-Dquarkus.profile=prod; - Secrets via Kubernetes ConfigMap/Secret: автоматическое монтирование как
configmap:/иsecret:/; - Config encryption: через
smallrye-configи внешние провайдеры (Vault, KMS).
Пример application.properties в Quarkus:
%dev.app.url=http://localhost:8080
%prod.app.url=https://api.example.com
quarkus.datasource.db-kind=postgresql
quarkus.datasource.username=${db.user}
quarkus.datasource.password=${db.password}
Переменные db.user, db.password могут поступать из Kubernetes Secret.
9.11. Сравнение с Spring Boot Config
| Критерий | MicroProfile Config | Spring Boot Config |
|---|---|---|
| Стандартизация | Jakarta EE / MicroProfile | Proprietary (Pivotal/VMware) |
| Иерархия источников | ordinal-приоритет | Жёсткий порядок (17+ уровней) |
| Типобезопасность | @ConfigProperties (MP 3.0+) | @ConfigurationProperties (с 1.0) |
| Динамическая перезагрузка | Опционально (runtime-зависимо) | Через Spring Cloud Config + @RefreshScope |
| CDI-интеграция | Встроенная | Требует Spring Context |
| Профили | %profile.key=value | application-{profile}.properties |
| Конвертация | Встроенная + Converter | Встроенная + Converter/Formatter |
✅ MicroProfile Config легче встраивается в non-Spring среды (Quarkus, Helidon, Open Liberty).
✅ Spring Boot Config богаче в enterprise-интеграциях (Vault, Consul, AWS и др. «из коробки»).
10. Конфигурация сетевых и HTTP-клиентов
Java предоставляет два поколения HTTP-клиентов:
- Legacy:
java.net.URL,URLConnection,HttpURLConnection(Java 1.0+); - Modern:
java.net.http.HttpClient(Java 11+, incubated в 9–10).
Оба поддерживают HTTPS, прокси, аутентификацию, кастомные заголовки. Современный клиент добавляет HTTP/2, reactive streams, строгую типизацию.
10.1. java.net.http.HttpClient (Java 11+)
10.1.1. Создание клиента
HttpClient client = HttpClient.newBuilder()
.connectTimeout(Duration.ofSeconds(10))
.followRedirects(HttpClient.Redirect.NORMAL) // NEVER, ALWAYS
.version(HttpClient.Version.HTTP_2) // HTTP_1_1, HTTP_2
.sslContext(sslContext) // кастомный SSLContext
.sslParameters(sslParameters) // кастомные параметры TLS
.executor(executor) // кастомный Executor (по умолчанию ForkJoinPool.commonPool())
.cookieHandler(cookieManager) // управление cookie
.authenticator(authenticator) // HTTP-аутентификация
.proxy(proxySelector) // выбор прокси
.build();
10.1.2. connectTimeout
- Применяется к
connect()сокета; - Не влияет на
readTimeout(устанавливается вHttpRequest.Builder); - Значение
Duration.ZERO— отключает таймаут.
10.1.3. followRedirects
| Значение | Поведение |
|---|---|
HttpClient.Redirect.NEVER | Не следовать за редиректами (3xx) |
HttpClient.Redirect.NORMAL | Следовать за GET/HEAD, не за POST/PUT/DELETE (стандарт RFC 7231) |
HttpClient.Redirect.ALWAYS | Следовать за всеми (опасно для неидемпотентных методов) |
10.1.4. Версии HTTP
| Версия | Поддержка |
|---|---|
HTTP_1_1 | Всегда доступна |
HTTP_2 | Доступна только при HTTPS и поддержке ALPN на стороне сервера |
Авто (null) | Попытка HTTP/2 → откат на HTTP/1.1 |
🔹 HTTP/2 требует TLS 1.2+ и ALPN (Application-Layer Protocol Negotiation).
🔹 В JDK 11+ ALPN встроен вsun.security.ssl.ALPNExtension.
10.1.5. Асинхронные операции
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.example.com/data"))
.timeout(Duration.ofSeconds(30)) // read timeout
.header("User-Agent", "MyApp/1.0")
.GET()
.build();
// Блокирующий вызов
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
// Асинхронный вызов (CompletableFuture)
CompletableFuture<HttpResponse<String>> future = client.sendAsync(request, HttpResponse.BodyHandlers.ofString());
10.1.6. Тела запросов
| Тип | Метод | Пример |
|---|---|---|
| Строка | BodyPublishers.ofString("text") | POST("text", BodyPublishers.ofString(body)) |
| Файл | BodyPublishers.ofFile(path) | PUT(BodyPublishers.ofFile(Paths.get("data.json"))) |
| Поток | BodyPublishers.ofInputStream(() -> in) | POST(BodyPublishers.ofInputStream(() -> new ByteArrayInputStream(bytes))) |
| Reactive | BodyPublishers.fromPublisher(publisher) | Для Flow API |
10.1.7. Обработка ответов
| Обработчик | Описание |
|---|---|
BodyHandlers.ofString() | Строка (по умолчанию UTF-8) |
BodyHandlers.ofInputStream() | InputStream (ленивая загрузка) |
BodyHandlers.ofFile(path) | Сохранение в файл |
BodyHandlers.discarding() | Игнорирование тела |
BodyHandlers.ofLines() | Stream<String> по строкам |
BodyHandlers.fromLineSubscriber(subscriber) | Reactive streams |
10.2. HttpURLConnection / URLConnection (legacy)
10.2.1. Базовое использование
URL url = new URL("https://api.example.com/data");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setConnectTimeout(10_000);
conn.setReadTimeout(30_000);
conn.setRequestProperty("User-Agent", "MyApp/1.0");
int status = conn.getResponseCode();
String body;
try (InputStream in = conn.getInputStream()) {
body = new String(in.readAllBytes(), StandardCharsets.UTF_8);
}
10.2.2. Настройки подключения
| Метод | Описание |
|---|---|
setConnectTimeout(int ms) | Таймаут установки TCP-соединения |
setReadTimeout(int ms) | Таймаут между байтами при чтении |
setUseCaches(boolean) | Использовать кэш (только для GET, если ResponseCache установлен) |
setChunkedStreamingMode(int chunklen) | Отправка тела чанками (для больших POST) |
setFixedLengthStreamingMode(int len) | Фиксированная длина тела (Content-Length) |
setInstanceFollowRedirects(boolean) | Следовать редиректам (по умолчанию true) |
10.2.3. Кэширование
ResponseCache.setDefault(new MyResponseCache());
// MyResponseCache extends ResponseCache
public CacheResponse get(URI uri, String rqstMethod, Map<String, List<String>> rqstHeaders) { … }
public CacheRequest put(URI uri, URLConnection conn) throws IOException { … }
Поддерживается только для GET, HEAD.
10.3. Прокси-настройки
10.3.1. Глобальные настройки
Через системные свойства:
-Dhttp.proxyHost=proxy.local -Dhttp.proxyPort=3128
-Dhttps.proxyHost=proxy.local -Dhttps.proxyPort=3128
-Dhttp.nonProxyHosts="localhost|127.0.0.1|*.intranet"
10.3.2. Программные настройки
Для HttpClient:
ProxySelector proxySelector = ProxySelector.of(new InetSocketAddress("proxy.local", 3128));
HttpClient client = HttpClient.newBuilder()
.proxy(proxySelector)
.build();
Или кастомный:
ProxySelector customSelector = new ProxySelector() {
@Override
public List<Proxy> select(URI uri) {
if (uri.getHost().endsWith(".intranet")) {
return List.of(Proxy.NO_PROXY);
}
return List.of(new Proxy(Proxy.Type.HTTP, new InetSocketAddress("proxy.local", 3128)));
}
@Override
public void connectFailed(URI uri, SocketAddress sa, IOException ioe) {
logger.warn("Proxy failed for {}: {}", uri, sa, ioe);
}
};
Для HttpURLConnection:
Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("proxy.local", 3128));
HttpURLConnection conn = (HttpURLConnection) new URL("https://example.com").openConnection(proxy);
10.4. TLS/SSL-конфигурация
10.4.1. Создание SSLContext
KeyStore trustStore = KeyStore.getInstance("JKS");
try (InputStream in = Files.newInputStream(Paths.get("trust.jks"))) {
trustStore.load(in, "changeit".toCharArray());
}
TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX");
tmf.init(trustStore);
SSLContext sslContext = SSLContext.getInstance("TLSv1.3");
sslContext.init(null, tmf.getTrustManagers(), null);
10.4.2. SSLParameters
SSLParameters params = sslContext.getDefaultSSLParameters();
// Протоколы
params.setProtocols(new String[]{"TLSv1.2", "TLSv1.3"});
// Шифронаборы
params.setCipherSuites(new String[]{
"TLS_AES_128_GCM_SHA256",
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384"
});
// ALPN (для HTTP/2)
params.setApplicationProtocols(new String[]{"h2", "http/1.1"});
// Hostname verification
params.setEndpointIdentificationAlgorithm("HTTPS"); // включает проверку CN/SAN
🔹
setEndpointIdentificationAlgorithm("HTTPS")— аналогHttpsURLConnection.getDefaultHostnameVerifier().
10.4.3. Отключение проверки сертификатов (только для тестов!)
TrustManager[] trustAll = new TrustManager[]{
new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; }
public void checkClientTrusted(X509Certificate[] certs, String authType) {}
public void checkServerTrusted(X509Certificate[] certs, String authType) {}
}
};
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, trustAll, new SecureRandom());
HttpClient client = HttpClient.newBuilder()
.sslContext(sslContext)
.sslParameters(new SSLParameters())
.build();
❌ Запрещено в production.
10.5. Аутентификация
10.5.1. Authenticator (глобальный)
Authenticator.setDefault(new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
if ("api.example.com".equals(getRequestingHost())) {
return new PasswordAuthentication("user", "pass".toCharArray());
}
return super.getPasswordAuthentication();
}
});
Поддерживает:
- Basic;
- Digest;
- NTLM (на Windows);
- Negotiate (Kerberos/SPNEGO, если настроен JAAS).
10.5.2. Явные заголовки
String credentials = Base64.getEncoder().encodeToString("user:pass".getBytes(UTF_8));
HttpRequest request = HttpRequest.newBuilder()
.header("Authorization", "Basic " + credentials)
.GET()
.build();
10.5.3. OAuth2 / Bearer
HttpRequest request = HttpRequest.newBuilder()
.header("Authorization", "Bearer " + accessToken)
.GET()
.build();
10.6. Управление cookie
10.6.1. CookieHandler
CookieManager cookieManager = new CookieManager(
new FileCookieStore(Paths.get("cookies.txt")), // кастомный хранилище
CookiePolicy.ACCEPT_ORIGINAL_SERVER
);
HttpClient client = HttpClient.newBuilder()
.cookieHandler(cookieManager)
.build();
Политики:
CookiePolicy.ACCEPT_ALL— принимать все;CookiePolicy.ACCEPT_NONE— игнорировать;CookiePolicy.ACCEPT_ORIGINAL_SERVER— только от исходного домена (без 3rd-party).
10.6.2. Ручное управление
HttpResponse<String> loginResponse = client.send(loginRequest, BodyHandlers.ofString());
String cookies = loginResponse.headers().firstValue("Set-Cookie").orElse("");
HttpRequest dataRequest = HttpRequest.newBuilder()
.header("Cookie", cookies)
.GET()
.build();
10.7. HTTP/2 и ALPN
10.7.1. Требования для HTTP/2
- HTTPS (TLS 1.2+);
- Поддержка ALPN на сервере;
SSLParameters.setApplicationProtocols(new String[]{"h2", "http/1.1"});- JDK ≥ 9 (ALPN встроен).
10.7.2. Проверка версии
HttpResponse<Void> response = client.send(request, BodyHandlers.discarding());
System.out.println(response.version()); // HTTP_2 или HTTP_1_1
10.7.3. HTTP/3 (QUIC)
- В JDK не поддерживается (на 2025 год);
- Требует сторонних библиотек: AHC (Async HTTP Client), Jetty HttpClient, Netty.
10.8. Безопасность: OCSP, CRL, Hostname Verification
10.8.1. Включение OCSP stapling
Security.setProperty("ocsp.enable", "true");
10.8.2. Проверка отзыва сертификатов
System.setProperty("com.sun.net.ssl.checkRevocation", "true");
Security.setProperty("jdk.security.certpath.revocationCheck", "PREFER_CRLS");
Возможные значения:
PREFER_CRLS— сначала CRL, потом OCSP;PREFER_OCSP— наоборот;NO_FALLBACK— без отката.
10.8.3. Hostname verification
- По умолчанию в
HttpsURLConnectionиHttpClient— включена приsetEndpointIdentificationAlgorithm("HTTPS"); - Проверяет:
SubjectAlternativeName(SAN) DNS-имена;- при отсутствии SAN —
CommonName(CN) вSubjectDN; - нечувствительно к регистру;
- поддерживает wildcard (
*.example.com→api.example.com, но неa.b.example.com).
10.9. Диагностика и отладка
10.9.1. Логирование SSL
-Djavax.net.debug=ssl:handshake:verbose
10.9.2. Трассировка HTTP
HttpClient client = HttpClient.newBuilder()
.build();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://httpbin.org/get"))
.header("User-Agent", "Debug")
.GET()
.build();
HttpResponse<String> response = client.send(request, BodyHandlers.ofString());
System.out.println("Status: " + response.statusCode());
System.out.println("Headers: " + response.headers().map());
System.out.println("Body: " + response.body());
10.9.3. Перехват запросов/ответов
Через HttpClient.Builder.executor() и кастомный Flow.Subscriber, или через прокси (mitmproxy, Charles).