惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

A
About on SuperTechFans
Y
Y Combinator Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Microsoft Security Blog
Microsoft Security Blog
aimingoo的专栏
aimingoo的专栏
I
InfoQ
C
Check Point Blog
IT之家
IT之家
MyScale Blog
MyScale Blog
Apple Machine Learning Research
Apple Machine Learning Research
Vercel News
Vercel News
Last Week in AI
Last Week in AI
GbyAI
GbyAI
P
Proofpoint News Feed
量子位
Stack Overflow Blog
Stack Overflow Blog
Microsoft Azure Blog
Microsoft Azure Blog
月光博客
月光博客
阮一峰的网络日志
阮一峰的网络日志
人人都是产品经理
人人都是产品经理
B
Blog
T
The Blog of Author Tim Ferriss
H
Help Net Security
云风的 BLOG
云风的 BLOG

Все публикации подряд на Хабре

Ловим музу за клавиатуру: как айтишнику стать автором Что умеет Midjourney в 2026? Мой немного грустный разбор этого шикарного инструмента Никто не любит писать тесты, но ИИ может исправить это IPv8 выглядит как мечта. Поэтому почти наверняка не взлетит Производители вернули в продажу материнки с DDR3. Что происходит? Управление агентом с телефона через Telegram теперь в KodaCode От координации к лидерству: как меняется роль руководителя разработки Я сделала родителям бизнес вместо пенсии: зарабатываем 70 тысяч, мама не даёт продать В три раза быстрее приемка товара и оптимизация трудозатрат на 73%: как «РСТ-Инвент» помог Gulliver Group ИИ-шечный мир победил? О влиянии искусственного интеллекта на игропром Кремль снижает давление на Телеграмм пока Европа строит интернет по паспорту Как CEO, CTO и CIO за 8 часов собрали ИИ-директора, который умеет держать позицию под давлением Как (не) потерять домен за выходные Вместо 8 разных VPS: как я организовал практику студентам на одном сервере Почему твой Open Source проект не замечают? R&D: искусство управления неопределенностью в разработке AI-дефляция: вакансий для разработчиков больше, а рост зарплат — худший за 15 лет Мы отдали управление роботами OpenClaw. Что из этого вышло Галактический ID: система идентификации для всех форм разумной жизни Шесть основ бизнес-анализа: начинаем с вопроса «Кто в игре?» Код-ревью, в котором дело не в коде Данные переехали. Команда — нет Системной подход к сдаче OSWE в 2025 Почему комната управления реактором покрашена в цвет морской пены 4 YAML-файла вместо PySpark: как аналитикам строить пайплайны без разработчиков LLM-агент для поиска свободных доменов: автоматизируем подбор Когда, зачем и как правильно начинать новую сессию в Claude Code? Как я заставил нейросеть писать макросы для FreeCAD Анатомия ИИ‑агента для подбора персонала. От тысячи резюме к топ‑10 за минуты Опыт разработчика как экономика внимания
Axelix. Cпецназ для Вашей Spring Boot экосистемы
Михаил Поливаха · 2026-06-01 · via Все публикации подряд на Хабре

Простой

9 мин

13K

Привет, Хабр!

Меня зовут Михаил Поливаха. Я думаю, что в Хабе Spring АйО меня уже относительно знают. В рамках Spring АйО мы довольно часто занимаемся подбором технического материала и его ревью. Сам же я довольно регулярно выступаю на конференциях, контрибьючу в Open Source и т.д.

Также, часто наши материалы крутятся вокруг Java разработки и конечно же Spring-а. И данной пост, хоть и будет с одной стороны сильно связан с Java и Spring Framework, но, тем не менее, не похож на остальные.

На днях произошло довольно знаковое событие. Мы с небольшой командой примерно год писали инструмент, который призван существенно упростить весь процесс отладки, тестирования и мониторинга Spring Boot приложений в production. И вот этот проект наконец-то получил первый Milestone Релиз.

Проект называется Axelix.

Думаю, что важно сразу отметить: ядро проекта Axelix является Open Source продуктом и доступно на GitHub. Проект будет следовать модели Open Core. Поэтому Вы можете спокойно ставить его себе в контур так же, как ставите, например, Grafana.

В данном посте я хочу рассказать про историю проекта, то, зачем он нужен, и как мы собтсвенно вообще к нему пришли. В нём будет анализ причин появления Axelix и глубокий обзор конкретного кейса решения повседневных проблем в рамках разработки на Spring Boot.

Надеюсь, что Вам будет интересно. Ну что же, начнём :)

Сотояние Индустрии Enterprise Софта

Типичный enterprise имеет много внутреннего софта. Этот софт решает разные задачи и обычно написан на нескольких языках программирования — Java, Go, C# и т.д. Один из самых популярных ЯП для server-side/backend-приложений в крупных компаниях — это Java. На это есть много исторических причин, но факт остаётся фактом.

Кроме того, самый популярный фреймворк для написания backend-приложений на Java — бесспорно Spring Boot. Очень упрощённо: это дополнительный слой поверх Spring Framework, который упрощает его конфигурацию (хотя, сейчас Spring Boot уже гораздо больше, чем просто автоконфигурация). По ряду причин это безоговорочно самый популярный выбор в enterprise. Например, Netflix мигрировал свою экосистему (более 3000 приложений) на Spring Boot 3 и планирует оставаться на Spring Boot.

Итого: Spring Boot победил. Это очень популярный выбор на backend при разработке на Java. Это то, что у нас есть сегодня и с этим странно спорить.

Мотивация и Pain Point

Что интересно: Spring Framework изначально начинался как IoC-контейнер с dependency injection в качестве главной фичи, а сейчас это совсем другое — намного, намного больше. Сегодня Spring Framework / Spring Boot — целая экосистема, которая поддерживает весь технологический стек нашего приложения:

  • Обработка HTTP-запросов

  • Работа с RDBMS — от управления транзакциями до ORM

  • Отправка сообщений в message broker-ы и многое другое

В результате экосистема Spring Framework существенно выросла в сложности. В современных Spring Boot microservice-ах у нас очень много движущихся частей. Например:

  • В приложениях много bean-ов. Часть приходит из Spring Boot и auto-configuration, часть — из внутренних платформенных библиотек, которые мы используем в компании, а часть мы создаём сами.

  • У нас довольно много properties, которые могут приходить из разных источников: из файла application.yaml, из Spring Cloud Config, из environment переменных внутри Pod-ов в K8S, из аргументов командной строки и так далее.

  • Конечно же, у нас много proxy! И все они работают друг с другом: transactional proxy, proxy для OpenFeign client-ов, proxy для Kafka Listener-ов и т.д.

Идея в том, что Spring Framework стал довольно большим и породил много взаимосвязанных частей, где каждая влияет на другую (например, properties влияют на создание bean-ов, созданные bean-ы могут подтянуть ещё properties и т.д.). Есть даже такое мнение, что из-за всего этого Spring Framework превратился в большого неукротимого монстра.

Подумайте сами: почти на любой Java-конференции — и внутри России, и даже за рубежом (говорю как спикер на международных конференциях, в том числе) — добрая половина докладов посвящена Spring Framework, тому как он устроен, или похожим темам.

Почему? Потому что Spring а) везде, и б) он сложен!

И, следуя из этого, за годы написания Spring Boot-приложений я с почти 100%-ной уверенностью могу сказать: когда мы, Java-разработчики на Spring Boot, деплоим приложения в любое окружение, мы снова и снова сталкиваемся с одними и теми же проблемами. Например:

  1. Мы делаем HTTP-запросы внутри транзакций и исчерпываем пул db-connection-ов.

  2. Мы создаем N + 1 и сталкиваемся с проблемами lazy loading в Spring Data JPA.

  3. Мы дебажим ситуации, когда в @Value / @ConfigurationProperties подтянулось не то property.

  4. Мы дебажим случаи, когда наш @Bean был “подавлен” из-за какого-то bean-а из @AutoConfiguration или платформенной либы и так далее…

Все эти проблемы реальны. Если Вы писали Spring Boot-приложения хотя бы пару лет, уверен, хотя бы часть из них Вам знакома.

А теперь: что, если я скажу, что боль от разработки Spring Boot backend-ов можно облегчить?

Вдумайтесь: сегодня по всему миру сотни и сотни команд пишут Spring Boot backend-ы и снова и снова борются с одними и теми же проблемами.

Можно ли это как-то решить? Давайте попробуем разобраться на примере.

Типичный День Spring Boot-разработчика

Чтобы глубже понять, что именно Axelix пытается решить, пройдёмся по паре примеров Java-кода. Представьте, что в приложении есть следующий код ниже. У нас есть Spring бин, который мы используем, чтобы получить набор permissions, которыми обладает гипотетический клиент:

@Slf4j
@Service
public class PermissionsResolver {

    @Value("${permission.caching.enabled:true}")
    private boolean cacheLookupsEnabled;

    @Autowired
    private ExternalPermissionsResolver delegate;

    @Autowired
    private PermissionsCache cache;
    
    @Autowired
    private DetailsResolver detailsResolver;

    @PostConstruct
    void init() {
        log.debug("Permissions cache lookup enabled: {}", cacheLookupsEnabled);
    }

    @Transactional
    public Set<PermissionDto> resolveClientPermissions(Client client) {
        try {
            Set<PermissionDto> permissions = delegate.resolve(client);
            
            for (Permission permission : permissions) {
                PermissionDetails details = detailsResolver.resolvePermissionDetails(permission);
                permission.setDetails(details);
            }
            
            return permissions;
        } catch (SomeExpectedException e) {
            if (cacheLookupsEnabled && client.getStatus() == ClientStatus.EXISTING) {
                log.debug("For the client '{}' taking permissions from the cache", client.getId());
                return cache.get(client.getId());
            } else {
                throw e;
            }
        }
    }
}

Это классический Java-код на стеке Spring Boot. Давайте честно: мы же все такое видели. Все такой код отлаживали, все много-много раз дорабатывали такой код.

И во время регрессионного тестирования QA-инженер приходит и говорит:

Привет! На dev/qa/sandbox/pre-prod окружении я не могу создать XYZ — пишет, что у моего client-а нет нужных permissions

Вы открываете IDE (или AI Agent, что уж там 😈) и пытаетесь разобраться в кодовой базе. Ищете, что может пойти не так.

Часть 1. Смена Уровня Логирования

А вариантов того, что может пойти не так в Spring Boot приложении — просто вагон.

Например, может оказаться, что мы берём client-ов из кэша. Ну, по крайней мере, кэш должен быть включён, верно? Или нет… И, как всегда, нужный нам log — в DEBUG, а не в INFO. И, конечно, logback — дефолтная система логирования под Spring Boot — его отфильтровывает и не пропускает.

Разве не было бы круто временно поднять уровень логирования для этого класса до DEBUG? Без редеплоя, буквально на 10 минут? Axelix позволяет временно изменить уровень логирования — только для отладки, — а потом откатить его назад. Кстати, очень скоро Axelix сможет откатить уровень логгирования сам, без необходимости разработчику вручную возвращать всё как было.

Часть 2. Загадочное Значение Property

Вы копаете дальше и понимаете: поведение некорректно, потому что на pre-prod мы вообще не должны брать client-ов из кэша. Мы должны упасть и вернуть соответствующий status code.

Теперь вопрос: почему, чёрт возьми, кэш вообще включён? Мы же явно отключили его через переменную окружения… Может, где-то есть другой property (например, из Spring Cloud Config), который переопределяет наш? А что, если Spring вообще не увидел нашу переменную окружения, отключающую кэш?

Это открытые вопросы, и поверьте, Вы не один такой. С этим сталкивается очень много людей.

Axelix может не только показать, какие properties знает Spring, но и сказать, какое property в итоге победило и подавило остальные — и откуда оно пришло.

Часть 3. Зоопарк Bean-ов

Ладно, Вы выяснили, что property на самом деле пришло из VCS через Spring Cloud Config, и какой-то инженер просто его поменял и забыл сказать (упс, как неловко-то вышло). Вы, скаля зубы, выключили кэширование и попросили QA перезапустить сценарий. Client, очевидно, по-прежнему без permissions, но хотя бы теперь мы отдаём ошибку, а не ответ из fallback-кэша.

Теперь нужно понять, почему permissions нет. QA мамой клянётся, что добавил их в базу данных или попросил кого-то это сделать. Вы ему доверяете, но (не на все 100%, конечно) и снова открываете IDE. И вот что находите:

public interface ExternalPermissionsResolver {

    Set<PermissionDto> resolve(Client client);
}

@Component
@ConditionalOnProperty(prefix = "permissions.resolver", value = "source", havingValue = "legacy", matchIfMissing = true)
@ConditionalOnMissingBean(ExternalPermissionsResolver.class)
public class LegacySystemPermissionsResolver implements ExternalPermissionsResolver {

    @Override
    public Set<PermissionDto> get(Client client) {
        // implementation
    }
}

@Component
@ConditionalOnProperty(prefix = "permissions.resolver", value = "source", havingValue = "database")
@ConditionalOnDatabaseAvailable
@ConditionalOnMissingBean(ExternalPermissionsResolver.class)
public class DatabaseSystemPermissionsResolver implements ExternalPermissionsResolver {

    @Override
    public Set<PermissionDto> get(Client client) {
        // implementation
    }
}

Итак, на pre-prod мы не хотим использовать старый LegacySystemPermissionsResolver — мы от него избавляемся. Есть ли шанс, что он всё ещё используется? По крайней мере, мы можем посмотреть properties и их фактические значения — Axelix уже помогает с этим. Однако это ещё не отвечает на главный вопрос: а мы на 100% уверены, что используем DatabaseSystemPermissionsResolver? А что, если нет?

Здесь Axelix может не только сказать, какие bean-ы реально активны, но и объяснить, откуда они взялись. Более того, Axelix может объяснить, почему bean-ы, которые мы ожидали увидеть созданными, на самом деле не были созданы.

Например, наш DatabaseSystemPermissionsResolver мог не создаться, потому что кастомная conditional-аннотация @ConditionalOnDatabaseAvailable не прошла, — и в итоге создался fallback LegacySystemPermissionsResolver.

Часть 4. Hibernate всегда рядом, чтобы всё испортить

Уже измотанный, измучанный, бедняга, Вы решили и эту проблему. Причина сломанных permissions — использование не того ExternalPermissionsResolver. Тестирование на pre-prod завершено, наконец. Столько времени ушло на отладку — это просто безумие!. Но разработчики для этого и существуют, чтобы страдать. Вы это принимаете и возвращаетесь к работе.

Только собрались с мыслями, сели за тикет — прилетает отчёт от нагрузочного тестирования:

95-й перцентиль latency улетел в космос: 5–6 секунд! Такое нельзя в прод катить!

Приложение под нагрузкой почему-то начинает тормозить. Вы не знаете, в чём дело. Но раз мы меняли только логику разрешения permissions, проблема, должно быть, где-то там.

Вы снова внимательно смотрите на код и понимаете:

Чёрт! Снова N + 1! DatabaseSystemPermissionsResolver возвращает entity без JOIN FETCH-нутой коллекции permissions!

Дъявол! А ведь проблема с N + 1 коварна тем, что её не так просто поймать в тестах! Конечно, Hibernate даёт статистику для её детекта, но никто же не заморочился писать тесты с глубоким анализом Hibernate statistics!

И этот код успешно прошёл:

  1. Code Review

  2. Quality Gate

  3. Функциональное тестирование от QA

  4. Security проверки от Sonar Qube и т.д.

Все барьеры пройдены! А теперь… Теперь нужно менять код, мержить, перетестировать, заново гонять security scan. Это такая боль! В агонии начинаете чувствовать, что ненавидите работу, а Hibernate — ещё больше, потому что всё так неочевидно!

Но не переживайте — Axelix может помочь. Axelix может обнаружить N + 1 запросы на testing/qa/sandbox окружениях задолго до деплоя на pre-prod или стенд нагрузочного тестирования.

Вот и всё. Более того, Вы не только можете обнаружить N + 1 запросы, но и точно сказать, какие запросы Hibernate выполнил под капотом в рамках этой @Transactional и сколько она длилась.

Наконец, если не хотите использовать UI Axelix, в ближайшем будущем можно будет настроить экспорт этих данных в любое APM-решение на Ваш вкус — от простого экспорта дополнительных Prometheus Metrics, до современного Open Telemetry — и смотреть те же данные из Axelix в привычной Grafana, например.

Интеграция с AI. MCP Server.

Фичи выше — это примерно ~30% того, что Axelix умеет сейчас; там гораздо больше. Я не перечисляю всё, иначе статья станет очень длинной. Но есть ещё один слон в посудной лавке, которого нельзя игнорировать — AI.

Сегодня мы все пользуемся AI Agent-ами: Cursor, Codex, Claude и т.д. Давайте честно: они занимают значительную часть нашей жизни как Software Engineer-ов. В Axelix мы это прекрасно понимаем; у нас AI:

  • Помогает ревьюить код в monorepo

  • Помогает писать интернационализированную документацию и т.д.

Мы признаём влияние и ценность AI. Поэтому во всех дистрибутивах Axelix идёт встроенный MCP server, который отдаёт все описанные выше (и не только) возможности AI Agent-у через embedded MCP server. Хотите отлаживать проблемы через AI Agent — пожалуйста.

Правило, которому мы следуем: всё, что доступно человеку через UI, также доступно AI Agent-ам через MCP server.

Сравнение со Spring Boot Admin

Уверен, опытные разработчики слышали про Spring Boot Admin. Этот инструмент работает как proxy к существующим Spring Boot Actuator endpoint-ам и даёт часть возможностей, которые умеет Axelix.

Мы настолько часто объясняли, чем Axelix отличается от Spring Boot Admin, что даже сделали отдельную страницу в документации, где объясняем, какие проблемы со Spring Boot Admin мы видим и какую роль Axelix играет в общей картине. Прочитайте, если интересно.

Заключение. Что дальше

Повторю: мы только что выпустили первый milestone. GA-релиза пока нет, но мы планируем его во второй половине лета 2026 года. Чтобы быть в курсе, мы завели telegram-канал для новостей о фичах и релизах. Подписывайтесь, если хотите следить за проектом.

У нас уже есть pilot-команды, которые поставили Axelix в свои окружения — как Helm Chart, Docker image или даже просто JAR. Мы по-прежнему активно обрабатываем feedback от пилотных команд. Если хотите поставить Axelix — Вы уже можете это сделать, документация доступна на русском и английском. В этом случае Вы сможете дать feedback и существенно повлиять на развитие Axelix.

Мы активно полируем документацию; если понадобится помощь — пишите напрямую администраторам Telegram-канала проекта Axelix. Поможем с установкой.

Надеюсь, статья была интересной. Если любопытно, как это устроено — исходники Axelix Core на GitHub. Изучайте на здоровье!

P.S: Мы приветствуем контрибьюторов! Хотите помочь — загляните в contribution guidelines нашего проекта. Будем рады увидеть PR/Issue от Вас когда-нибудь!