JavaRush /Курсы /Spring Boot /Condition evaluation report в Spring Boot

Condition evaluation report в Spring Boot

Spring Boot
8 уровень , 3 лекция
Открыта

1. Condition evaluation report: факты

Любая магия в программировании заканчивается ровно в тот момент, когда что-то пошло не так, а дедлайн — пошёл. Spring Boot очень удобен, пока вы довольны результатом. Но как только появляется вопрос «почему оно стартует так», «почему не появился нужный bean», «почему вдруг включилась какая-то подсистема», хочется не философии, а фактов.

Условия и default/backoff уже дали нам правила, но пока это всё видно только в теории. Когда приложение ведёт себя неожиданно, нужен способ прочитать уже принятые решения Boot, а не гадать по логам и собственным догадкам.

Condition evaluation report — это как чек-лист пилота: самолёт (приложение) взлетел, но вы можете посмотреть, какие системы включились, какие — нет, и что именно было сигналом для решения. Без отчёта новичок обычно либо гадает, либо лезет в интернет, либо (классика жанра) пытается «переопределить всё», чтобы стало «как он понимает». Отчёт нужен, чтобы сначала понять, а уже потом что-то менять.

Представьте catalog-service: даже без сложного web-слоя вы уже видите в логах, что поднимается embedded server, что где-то «сам» появился JSON-mapper, а какие-то штуки, наоборот, не включились. Condition report помогает воспринимать это не как «Boot живёт своей жизнью», а как систему правил, которую можно прочитать.

2. Включение отчёта: debug и способы

Condition evaluation report не прячется за секретным рукопожатием. Spring Boot просто не печатает его всегда, потому что вывод получается очень длинным, а консоль — не резиновая. Поэтому режим «покажи всё, что ты решил» включается явно. Хорошая новость: для этого не нужно писать ни одного «специального» класса, это обычная настройка запуска.

Важно сразу зафиксировать ожидание: когда вы включаете debug-режим, вы получаете много текста. Это нормально. И это не «шум», если вы читаете его правильно: не подряд, а отвечая на конкретный вопрос. А ещё debug-режим обычно держат включённым только на время диагностики — иначе в логах будет ощущение, что приложение не стартует, а пишет мемуары.

Ниже — три адекватных способа включить отчёт (и все они сводятся к одному и тому же флагу).

Способ Где задаём Пример
Через application.yaml В ресурсах проекта debug: true
Через аргумент запуска Команда запуска приложения --debug
Программно в main() В коде CatalogServiceApplication setDefaultProperties(Map.of("debug","true"))

Здесь debug нас интересует только как переключатель диагностики старта. Мы не строим вокруг него конфигурационную модель приложения; важно увидеть сам факт: Boot читает этот флаг как обычное свойство и печатает report.

Самый прямолинейный вариант — прописать debug: true в YAML. В учебном проекте это иногда удобно, но держать так постоянно — спорная идея (вы забудете выключить и будете жить в «режиме рассказчика»).

# src/main/resources/application.yaml
# Включаем печать condition evaluation report в логи старта приложения
debug: true

Второй вариант — включать debug флагом запуска. Например, если вы запускаете приложение с аргументами. В Gradle-режиме это тоже возможно, но здесь важно не уходить в детали сборки: достаточно знать, что Boot понимает --debug как «пожалуйста, напечатай condition evaluation report».

Третий вариант — программно. Он хорош именно как учебный, потому что вы видите: это всего лишь свойство, и Boot читает его так же, как любые другие настройки.

import java.util.Map;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class CatalogServiceApplication {

    public static void main(String[] args) {
        // Создаём SpringApplication вручную, чтобы добавить дефолтные свойства
        SpringApplication app = new SpringApplication(CatalogServiceApplication.class);

        // То же самое, что debug: true в application.yaml, только задано программно
        app.setDefaultProperties(Map.of("debug", "true"));

        // Запускаем приложение с переданными аргументами
        app.run(args);
    }
}

Если вы включили debug, в startup logs появится большой блок, начинающийся примерно как «CONDITIONS EVALUATION REPORT». Это и есть наша цель на сегодня: научиться читать его по-человечески.

3. Структура отчёта: positive и negative

Первое чувство, когда новичок видит condition report, почти всегда одинаковое: «Ого, сколько всего… и половина в negative… значит приложение сломалось?» Нет. Отчёт по своей природе обязан содержать огромное количество negative matches, потому что Spring Boot умеет очень много, а конкретное приложение использует лишь маленькую часть экосистемы.

В нашем catalog-service мы осознанно не подключаем JPA, Security, messaging и прочие штуки. Поэтому «не совпало условие» — это не ошибка, а нормальная констатация: «в этом приложении это не нужно». Более того, отрицательные совпадения — это ваше доказательство того, что Boot не «подмешал» вам случайно лишние подсистемы.

У отчёта довольно стабильная структура. В разных версиях Boot оформление может немного меняться, но смысл разделов одинаковый:

Раздел Что означает Как это читать
Positive matches Эти auto-configuration классы включились Ищем тут, если хотим понять, «почему что-то появилось»
Negative matches Эти auto-configuration классы не включились Ищем тут, если хотим понять, «почему чего-то нет»
Exclusions Что было исключено явно В нашем сценарии это почти не трогаем, но раздел можно узнать по имени
Unconditional classes Конфигурации без условий Они подключаются всегда (или почти всегда)

Внутри каждого пункта вы увидите примерно такую логику: имя auto-configuration класса и список причин, почему условие совпало или не совпало. Часто там фигурируют формулировки вроде @ConditionalOnClass found required class ... или did not find required class ..., а также условия на наличие/отсутствие beans или на значения properties.

Ниже — короткий, упрощённый пример (не пытайтесь дословно сравнивать со своим выводом, он зависит от версии и набора зависимостей; важна структура).

# Пример фрагмента отчёта (упрощённо): что включилось и почему
Positive matches:
-----------------
   DispatcherServletAutoConfiguration matched:
      - @ConditionalOnClass found required class 'org.springframework.web.servlet.DispatcherServlet'
      - @ConditionalOnWebApplication (Servlet) matched

# И что не включилось, с указанием причины
Negative matches:
-----------------
   WebFluxAutoConfiguration:
      Did not match:
         - @ConditionalOnClass did not find required class 'org.springframework.web.reactive.config.WebFluxConfigurer'

Здесь Boot буквально говорит: «MVC включаю, потому что классы MVC есть и приложение servlet-типа. WebFlux не включаю, потому что классов reactive MVC нет». Никакой мистики — просто проверка условий.

И теперь важная методическая мысль: condition report нельзя читать как роман. Если читать подряд, вы быстро захотите стать фронтендером (да, у нас тут не осуждают). Его читают как справку: «у меня есть вопрос → нахожу релевантный блок → читаю причины».

4. Чтение отчёта на практике

Чтобы condition evaluation report реально помогал, нужна простая дисциплина чтения. Без неё отчёт превращается в ту же «магическую простыню», только ещё длиннее. Хорошая новость: методика очень похожа на нормальную отладку: мы формулируем вопрос, ищем подтверждения, проверяем гипотезы и делаем вывод. Плохая новость: придётся на минуту перестать надеяться на интуицию и начать читать текст.

Ниже мы разберём три очень типовых сценария именно для уровня Boot-курса. Каждый сценарий — это вопрос, который реально возникает у новичка. И в каждом сценарии мы будем действовать одинаково: включаем debug, находим нужную auto-configuration по имени (обычно поиском по логам), читаем причины совпадения/несовпадения, а затем при необходимости сверяемся с фактическим содержимым ApplicationContext.

Когда нужно сверить вывод report с фактическим содержимым контекста, удобны одноразовые probe-компоненты: добавили один, посмотрели факт, убрали. Они не заменяют report, а просто дают второй взгляд на ту же ситуацию.

Сценарий: Tomcat и web-runtime без контроллеров

Когда вы запускаете Boot-приложение с web starter’ом, вы видите в логах что-то вроде «Tomcat started on port 8080». У новичка закономерный вопрос: «Я же не делал ничего вебового… почему оно подняло сервер?» Именно тут report прекрасен: он показывает, какие auto-config включились, чтобы собрать web-runtime.

В отчёте вы будете искать конфигурации, связанные с web server’ом и servlet-стеком. Часто в названии будет «Servlet», «WebServer», «Tomcat». Найдёте — и увидите причины. В здоровом сценарии там будут conditions по classpath (есть классы Tomcat) и по типу приложения (servlet web).

Упрощённый смысл таких строк обычно примерно такой: «класс Tomcat присутствует → значит, можно поднять embedded Tomcat → создаём фабрику web сервера, если пользователь не создал свою».

И вот здесь полезно сделать маленькую проверку фактов: какие именно «инфраструктурные» beans реально живут в контексте. Для этого удобно временно иметь в проекте небольшой ApplicationRunner, который печатает имена beans нужного типа. Это не замена отчёту, а «контрольный звонок»: отчёт говорит, почему что-то должно было включиться, а контекст показывает, что реально получилось.

Это снова временный probe, а не постоянный участник startup-кода.

import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.web.servlet.server.ServletWebServerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

@Component
class WebServerFactoryProbe implements ApplicationRunner {
    // Достаём контекст, чтобы посмотреть реальные бины, которые Boot создал на старте
    private final ApplicationContext context;

    WebServerFactoryProbe(ApplicationContext context) {
        this.context = context;
    }

    @Override
    public void run(ApplicationArguments args) {
        // Если web starter на classpath, то здесь обычно будет tomcatServletWebServerFactory
        var names = context.getBeanNamesForType(ServletWebServerFactory.class);

        // Печатаем имена бинов как «контрольный звонок» к condition report
        System.out.println("ServletWebServerFactory beans: " + String.join(", ", names));
        // ServletWebServerFactory beans: tomcatServletWebServerFactory
    }
}

Смысл прост: если web starter на classpath, Boot соберёт web runtime, и в контексте появится ServletWebServerFactory (обычно tomcat-реализация). Если starter убрать — bean исчезнет, и это будет видно и в отчёте (negative match), и в контексте (пустой список).

Здесь фокус не на обработке HTTP-запроса, а на самой платформенной вещи: web runtime — это инфраструктура, и Boot её собирает автоматически по условиям.

Сценарий: Jackson и JSON-инфраструктура из starter’ов

Второй частый сюрприз: через starter приходит Jackson, и у приложения появляется готовая JSON-инфраструктура. У новичка это выглядит так, будто Boot тайком добавил библиотеку. На самом деле всё скучнее (а значит, лучше): Jackson пришёл транзитивно через starter, а auto-configuration подхватила его, потому что классы JSON mapper’а есть на classpath.

В отчёте вы обычно ищете конфигурации, где в названии есть Jackson (например, JacksonAutoConfiguration). В Positive matches будет объяснение в духе: «найден класс JsonMapper, значит можно создать JSON mapper и зарегистрировать связанную инфраструктуру, если её ещё нет».

Чтобы убедиться, что mapper реально в контексте, можно снова «прозвонить» контекст. Это снова временный probe: он нужен только чтобы связать report с фактом.

import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import tools.jackson.databind.json.JsonMapper;

@Component
class JsonMapperProbe implements ApplicationRunner {
    // Смотрим, какие JsonMapper реально зарегистрированы в ApplicationContext
    private final ApplicationContext context;

    JsonMapperProbe(ApplicationContext context) {
        this.context = context;
    }

    @Override
    public void run(ApplicationArguments args) {
        // Если JSON mapper есть на classpath и вы не создали его сами, Boot добавит инфраструктурный бин
        var names = context.getBeanNamesForType(JsonMapper.class);

        // Выводим имена: это помогает связать «почему включилось» (report) и «что получилось» (контекст)
        System.out.println("JSON mapper beans: " + String.join(", ", names));
        // Обычно здесь увидите хотя бы один bean JSON mapper’а
    }
}

Очень важно не сделать неверный вывод. Наличие JSON mapper’а не значит, что вам срочно нужно его «переопределить» или «настроить правильно». Здесь важно другое: Boot включил его закономерно, потому что совпали условия. Точное имя бина сейчас несущественно; важен сам факт его появления как инфраструктурного default.

Сценарий: JPA, Security и WebFlux не включились — и это хорошо

Третий сценарий психологически самый важный. Вы включаете debug, видите гигантский раздел Negative matches и начинаете подозревать, что приложение «не до конца собралось». На самом деле это означает противоположное: приложение собралось ровно так, как нужно, и Boot не включил лишнего.

Для catalog-service это особенно принципиально. Это read-only сервис без БД, без Security и без reactive стека. Поэтому в отчёте вы должны увидеть отрицательные совпадения для конфигураций, связанных с JPA, Security и WebFlux. Причины обычно простые: нет нужных классов на classpath (потому что нет starter’а), не выполнены условия по типу приложения, нет нужных bean’ов.

Упрощённый «читаемый» пример мысли Boot выглядит так: «в проекте нет spring-boot-starter-data-jpa, значит нет классов EntityManager и друзей → auto-configuration JPA не включаем». Или: «нет spring-boot-starter-security, значит нет нужных классов Security → не включаем security auto-config».

И вот тут возникает полезная привычка: negative match — это доказательство, что вас не утащило в соседнюю технологию. Это не «что-то сломалось», это «условия не выполнены». Иногда это самое приятное место отчёта, потому что оно подтверждает: проект остаётся в границах.

Если хочется «потрогать руками», можно найти в отчёте одну-две строки, например про WebFlux, и прочитать причины. Они почти всегда будут вида «did not find required class ...». То есть Boot буквально говорит: «у тебя этого нет на classpath, поэтому я это не включаю». И это ровно то, что мы хотим видеть в базовом Boot-template, который не превращается в витрину всего Spring сразу.

Маленькие приёмы, чтобы отчёт не стал наказанием

Condition evaluation report — инструмент сильный, но он не пытается быть «красивым». Он честный. И поэтому есть несколько практичных приёмов, которые резко повышают его полезность, особенно для начинающего. Во-первых, всегда начинайте с вопроса в формате «почему X включилось?» или «почему Y не включилось?», а не с попытки понять весь Boot за один запуск. Во-вторых, ищите в отчёте по ключевым словам: имя auto-configuration класса, название технологии, иногда — имя класса, которого «не нашли».

Ещё одна рабочая привычка — сверять отчёт с фактом контекста. Отчёт показывает причины решения, но если вы хотите убедиться, что бин действительно создан, ApplicationContext даст прямой ответ. В этом смысле маленькие probe-компоненты (как в примерах выше) — это «фонарик»: вы не превращаете проект в диагностическую лабораторию, вы просто на минуту включаете свет и проверяете, что в комнате действительно стоит тот шкаф, про который вам рассказали.

Наконец, помните, что в отчёте много технических имён, и это нормально. Вам не нужно «знать все auto-config классы». Достаточно узнавать паттерны: OnClassCondition почти всегда про classpath, OnPropertyCondition — про свойства, OnBeanCondition и OnMissingBeanCondition — про наличие/отсутствие bean’ов. Через пару запусков эти слова перестают пугать и начинают работать как дорожные знаки: не красиво, но понятно.

5. Типичные ошибки при работе с condition evaluation report

Когда вы впервые включаете debug=true, очень легко сделать несколько типичных «новичковых» выводов, которые звучат логично, но ведут не туда. Самая частая проблема — пытаться читать отчёт как единый текст и переживать из‑за каждого negative match. Вторая — делать выводы по одному совпадению, не проверяя, что в итоге действительно создалось. Ниже — ошибки, которые встречаются чаще всего и больнее всего мешают учиться.

Ошибка №1: включить debug и пытаться прочитать отчёт сверху вниз, не имея вопроса.
Так вы получите только одно: усталость и желание спрятаться под столом вместе с котом. Отчёт полезен, когда вы идёте от конкретного «почему?» и ищете конкретный блок. Тогда даже огромный вывод превращается в справочник, а не в поток сознания Spring Boot.

Ошибка №2: воспринимать negative match как признак поломки приложения.
У нормального приложения negative matches всегда будет много, потому что Boot умеет больше, чем нужно вашему проекту. Для catalog-service отрицательные совпадения по JPA, Security и WebFlux — это вообще хороший признак: это подтверждение, что вы не утащили проект в чужую предметную область.

Ошибка №3: думать, что positive match автоматически означает «всё готово и работает».
Positive match говорит только одно: auto-configuration класс включился. Но итоговый эффект может зависеть от других условий и от того, какие beans реально создались. Поэтому полезно иногда сверяться с ApplicationContext: если вы ожидаете ServletWebServerFactory — проверьте, что он есть; если ожидаете JSON mapper — проверьте, что он действительно зарегистрирован.

Ошибка №4: игнорировать причины внутри negative match и застревать на заголовке.
Часто новичок видит название конфигурации и делает вывод «не включилось, значит плохо». Но смысл отчёта в причинах. Одна строчка «did not find required class ...» моментально объясняет, что это просто отсутствующий starter, а не загадочный баг в контейнере.

Ошибка №5: пытаться «починить» отчёт кастомизацией, не поняв причин.
Самый опасный путь — сразу лезть переопределять beans, добавлять аннотации и выключать auto-configuration, потому что «в отчёте что-то не нравится». Отчёт — это не список того, что надо срочно поменять. Это объяснение текущего поведения. Сначала читаем, понимаем, и только потом (если реально нужно) меняем приложение.

1
Задача
Spring Boot, 8 уровень, 3 лекция
Недоступна
Debug-отчет для положительного сценария
Debug-отчет для положительного сценария
1
Задача
Spring Boot, 8 уровень, 3 лекция
Недоступна
Debug-отчет для отрицательного сценария
Debug-отчет для отрицательного сценария
Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ