🍃 Раздел 5 · Вопрос #20

Что такое автоконфигурация в Spring Boot

Принцип работы формулируется как Convention over Configuration (Соглашение важнее конфигурации): вместо написания сотен строк XML или Java-конфигурации Spring Boot берет на себя...


🟢 Junior Level

Автоконфигурация (Auto-Configuration) — это ключевой механизм Spring Boot, который автоматически создает, связывает и настраивает бины в ApplicationContext на основе библиотек, обнаруженных в classpath, системных свойств (application.properties) и уже объявленных разработчиком компонентов.

Принцип работы формулируется как Convention over Configuration (Соглашение важнее конфигурации): вместо написания сотен строк XML или Java-конфигурации Spring Boot берет на себя рутину с разумными настройками по умолчанию (Opinionated Defaults).

Базовый пример: подключение БД

В классическом Spring Framework для подключения к PostgreSQL требовалось вручную настраивать DataSource, EntityManagerFactory, TransactionManager и пул HikariCP:

// Классический Spring (без Spring Boot) — десятки строк шаблонного кода:
@Configuration
public class ManualDbConfig {
    @Bean
    public DataSource dataSource() {
        HikariConfig config = new HikariConfig();
        config.setJdbcUrl("jdbc:postgresql://localhost:5432/mydb");
        config.setUsername("user");
        config.setPassword("pass");
        return new HikariDataSource(config);
    }
}

В Spring Boot достаточно:

  1. Добавить стартер в pom.xml / build.gradle: spring-boot-starter-data-jpa и драйвер postgresql.
  2. Указать параметры подключения в application.yml:
    spring:
      datasource:
        url: jdbc:postgresql://localhost:5432/mydb
        username: user
        password: pass
    
  3. Spring Boot сам обнаружит класс org.postgresql.Driver и библиотеку HikariDataSource в classpath и создаст готовый к работе бин DataSource.

Как отключить ненужную автоконфигурацию

// Отключение через аннотацию:
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

Или через конфигурационный файл:

spring:
  autoconfigure:
    exclude:
      - org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration

🟡 Middle Level

Пайплайн запуска автоконфигурации

Процесс запуска автоконфигурации координируется мета-аннотацией @SpringBootApplication:

@SpringBootApplication
         │
         ├──> @Configuration
         ├──> @ComponentScan (Сканирует пользовательские бины)
         └──> @EnableAutoConfiguration
                   │
                   ▼
         AutoConfigurationImportSelector
                   │
                   ▼
         Чтение реестра автоконфигураций (.imports / spring.factories)
                   │
                   ▼
         Фильтрация по условиям (@Conditional)
                   │
                   ▼
         Регистрация оставшихся конфигураций в ApplicationContext

Семейство аннотаций @Conditional

Автоконфигурация работает благодаря условным аннотациям (Conditions). Бин создается только при выполнении определенного критерия:

Аннотация Условие срабатывания
@ConditionalOnClass(Foo.class) Класс Foo физически найден в classpath.
@ConditionalOnMissingClass Класса нет в classpath.
@ConditionalOnBean(Bar.class) В контексте уже есть хотя бы один бин указанного типа.
@ConditionalOnMissingBean В контексте еще нет бина такого типа (позволяет разработчику переопределить бин).
@ConditionalOnProperty В application.yml задано свойство с определенным значением.
@ConditionalOnWebApplication Приложение является веб-приложением (сервлетным или реактивным).

Пример из исходников Spring Boot: JacksonAutoConfiguration

@AutoConfiguration
@ConditionalOnClass(ObjectMapper.class) // Сработает, только если подключен Jackson
public class JacksonAutoConfiguration {

    @Bean
    @Primary
    @ConditionalOnMissingBean // Создаст ObjectMapper ТОЛЬКО если разработчик не объявил свой!
    public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) {
        return builder.createXmlMapper(false).build();
    }
}

Золотое правило: Аннотация @ConditionalOnMissingBean — фундамент гибкости Spring Boot. Она означает: «Если программист не объявил собственный бин, контейнер предоставит дефолтный».

Отладка автоконфигурации: Condition Evaluation Report

Чтобы точно понять, почему определенный бин создался или был пропущен, запустите приложение с флагом --debug:

java -jar myapp.jar --debug

В консоль выведется подробный отчет CONDITIONS EVALUATION REPORT:

  • Positive matches: автоконфигурации, чьи условия выполнились.
  • Negative matches: автоконфигурации, которые были пропущены (с указанием точной причины, например: @ConditionalOnClass did not find [org.apache.kafka.clients.producer.Producer]).
  • Exclusions: исключенные конфигурации.

🔴 Senior Level

Эволюция механизмов: Spring Boot 2.x vs Spring Boot 3.x

До версии Spring Boot 2.7 для обнаружения автоконфигураций использовался файл META-INF/spring.factories. В Spring Boot 3.x этот механизм был заменен на специализированный файл реестра:

Spring Boot 2.x:
  META-INF/spring.factories
  Ключ: org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
        com.example.MyAutoConfiguration

Spring Boot 3.x (и 2.7+):
  META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
  Содержимое: простой список полных имен классов по одному на строку:
        com.example.MyAutoConfiguration

Почему формат был изменен:

  1. Поддержка GraalVM Native Image и Spring AOT: простой список классов намного быстрее анализируется статическими анализаторами во время Ahead-Of-Time компиляции.
  2. Производительность холодного старта: исключен оверхед на парсинг тяжелого Properties-файла со множеством разных SPI-ключей.

Как Spring Boot проверяет @ConditionalOnClass без ClassNotFoundException

Если бы Spring Boot проверял наличие классов через обычный Class.forName("org.postgresql.Driver"), отсутствующий драйвер привел бы к выбросу исключения ClassNotFoundException и остановке приложения.

Внутренний механизм:

Spring Boot анализирует метаданные классов автоконфигурации через низкоуровневый парсер байткода ASM (SimpleMetadataReaderFactory), не загружая сами классы в JVM Metaspace! Если ASM видит, что целевой тип отсутствует в ClassLoader, ветка конфигурации отбрасывается еще до загрузки класса конфигурации.

Порядок фаз: Почему @ComponentScan выполняется ДО автоконфигурации

Это фундаментальный архитектурный принцип:

  1. Сначала отрабатывает @ComponentScan: контейнер находит и регистрирует все пользовательские бины, помеченные @Component, @Service, @Repository, @Bean.
  2. Только после этого запускается AutoConfigurationImportSelector.
  3. Благодаря этому, когда автоконфигурация доходит до условий @ConditionalOnMissingBean, она уже «видит» все бины, созданные разработчиком, и уступает им приоритет.

Управление порядком автоконфигураций: @AutoConfiguration

Для координации зависимостей между разными автоконфигурациями используется аннотация @AutoConfiguration (пришедшая на смену @Configuration в стартерах):

package com.example.autoconfigure;

import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.context.annotation.Bean;

@AutoConfiguration(after = DataSourceAutoConfiguration.class) // Запустится СТРОГО ПОСЛЕ базы данных
@ConditionalOnClass(CustomAuditClient.class)
public class CustomAuditAutoConfiguration {

    @Bean
    @ConditionalOnMissingBean
    public CustomAuditClient customAuditClient() {
        return new CustomAuditClient();
    }
}

🎯 Шпаргалка для интервью

30-секундный ответ

Автоконфигурация — механизм Spring Boot, реализующий подход Convention over Configuration. Он автоматически регистрирует бины в контексте на основе библиотек в classpath, свойств конфигурации и текущего окружения.

  • Инициируется мета-аннотацией @EnableAutoConfiguration через класс AutoConfigurationImportSelector.
  • В Spring Boot 3.x список автоконфигураций считывается из файла META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports.
  • Регистрация бинов управляется семейством аннотаций @Conditional (главная из которых — @ConditionalOnMissingBean, позволяющая пользователю переопределять дефолтные бины).
  • Пользовательские бины из @ComponentScan регистрируются первыми, а автоконфигурация подключается после них.

4 каверзных вопроса с ответами

  1. Как Spring Boot проверяет условия @ConditionalOnClass, не вызывая ClassNotFoundException? Ответ: Spring Boot использует библиотеку ASM для чтения байткода (.class файлов) без фактической загрузки классов в память через ClassLoader. С помощью MetadataReader контейнер анализирует константный пул и сигнатуры типов. Если класс не может быть разрешен ClassLoader-ом, условие бракуется без фатальной ошибки.

  2. Почему автоконфигурации всегда запускаются ПОСЛЕ пользовательских классов конфигурации? Ответ: Чтобы разработчик приложения имел наивысший приоритет. Сначала выполняется сканирование компонентов приложения (@ComponentScan). Когда все кастомные бины зарегистрированы, запускается автоконфигурация, в которой срабатывают аннотации @ConditionalOnMissingBean. Если пользователь уже создал свой бин, автоконфигурация мирно отступает.

  3. В чём разница между META-INF/spring.factories и .imports-файлом в Spring Boot 3? Ответ: В Spring Boot 2.x все точки расширения (включая EnableAutoConfiguration) хранились в общем файле spring.factories формата Java Properties. В Spring Boot 3.x автоконфигурации вынесены в отдельный текстовый файл META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports, представляющий собой простой список классов. Это ускоряет старт приложения и необходимо для поддержки компиляции в Native Image (GraalVM / Spring AOT).

  4. Как определить, почему конкретная автоконфигурация не применилась к вашему проекту? Ответ: Запустить приложение с параметром --debug (или debug=true в application.properties) либо вызвать эндпоинт Spring Boot Actuator /actuator/conditions. В консоли появится ConditionEvaluationReport, где в разделе Negative matches указано конкретное невыполненное условие (например, отсутствие класса или свойства).

Красные флаги (чего категорически нельзя говорить)

  • ❌ «Автоконфигурация создает абсолютно все бины из всех стартеров в памяти» — создаются только те бины, для которых выполнились все условия @Conditional.
  • ❌ «В Spring Boot 3.x для написания стартера всё еще нужно использовать spring.factories» — в Boot 3.x автоконфигурации объявляются через .imports-файлы.
  • ❌ «Автоконфигурация замедляет выполнение HTTP-запросов в рантайме» — автоконфигурация работает строго один раз во время старта приложения и никак не влияет на рантайм-производительность.
  • ❌ «@ConditionalOnMissingBean сканирует библиотеки в classpath» — эта аннотация проверяет наличие бина в текущем ApplicationContext, а не файлы на диске.

Связанные темы