← Назад к вопросам

Как Spring Boot подгружает модули

2.0 Middle🔥 171 комментариев
#Spring Boot и Spring Data

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

# Как Spring Boot подгружает модули (Auto-configuration)

Короткий ответ

Spring Boot использует механизм Auto-configuration (автоконфигурация) с @EnableAutoConfiguration и условными аннотациями (@ConditionalOnClass, @ConditionalOnMissingBean и т.д.) для автоматической загрузки и конфигурации модулей на основе classpath и properties файлов.

Основной механизм: Spring Boot Auto-Configuration

Как это работает

1. Приложение запускается
   ↓
2. Spring Boot сканирует META-INF/spring.factories
   ↓
3. Загружает все классы auto-configuration
   ↓
4. Для каждого класса проверяет условия (@ConditionalOn*)
   ↓
5. Если условия выполнены → конфигурирует модуль
   ↓
6. Готово

Файл spring.factories

Это волшебный файл в META-INF директории каждой Spring Boot библиотеки.

Пример: spring-boot-starter-web

# Файл: spring-boot-starter-web/META-INF/spring.factories

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration,\
org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration,\
org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration,\
org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration

Пример: spring-boot-starter-data-jpa

# Файл: spring-boot-starter-data-jpa/META-INF/spring.factories

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\
org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration

Условные аннотации (Conditional Annotations)

Это условия, которые определяют, должна ли загружаться конфигурация.

1. @ConditionalOnClass

import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.context.annotation.Configuration;

@Configuration
@ConditionalOnClass(name = "javax.servlet.ServletContext")
public class WebServerAutoConfiguration {
    // Эта конфигурация загружается только если в classpath есть ServletContext
    // (то есть если добавлена зависимость spring-boot-starter-web)
    
    @Bean
    public ServletWebServerFactory servletWebServerFactory() {
        return new TomcatServletWebServerFactory();
    }
}

2. @ConditionalOnMissingBean

import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class JacksonAutoConfiguration {
    // Эта конфигурация загружается только если пользователь НЕ определил
    // собственный ObjectMapper bean
    
    @Bean
    @ConditionalOnMissingBean
    public ObjectMapper objectMapper() {
        return new ObjectMapper();
    }
}

3. @ConditionalOnProperty

import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Configuration;

@Configuration
@ConditionalOnProperty(name = "spring.h2.console.enabled", havingValue = "true")
public class H2ConsoleAutoConfiguration {
    // Загружается только если в application.properties/yml есть:
    // spring.h2.console.enabled=true
    
    @Bean
    public H2Console h2Console() {
        return new H2Console();
    }
}

4. @ConditionalOnBean

import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class TransactionAutoConfiguration {
    // Загружается только если в контексте уже существует DataSource bean
    
    @Bean
    @ConditionalOnBean(DataSource.class)
    public TransactionManager transactionManager(DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }
}

Порядок загрузки модулей

@AutoConfigureAfter и @AutoConfigureBefore

import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.context.annotation.Configuration;

// Загружается после DataSourceAutoConfiguration
@Configuration
@AutoConfigureAfter(DataSourceAutoConfiguration.class)
public class JpaAutoConfiguration {
    // Зависит от DataSource, поэтому должна загрузиться после
}

// Загружается ДО других конфигураций
@Configuration
@AutoConfigureBefore({JpaAutoConfiguration.class})
public class DataSourceAutoConfiguration {
    // Должна быть загружена первой
}

Практический пример: создание собственного Spring Boot Starter

Пример: Custom Email Starter

Шаг 1: Создаём конфигурацию

// Файл: com/example/mail/MailAutoConfiguration.java

import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;

@Configuration
@ConditionalOnClass(name = "javax.mail.Session")
@EnableConfigurationProperties(MailProperties.class)
public class MailAutoConfiguration {
    
    private final MailProperties mailProperties;
    
    public MailAutoConfiguration(MailProperties mailProperties) {
        this.mailProperties = mailProperties;
    }
    
    @Bean
    @ConditionalOnMissingBean
    public MailSender mailSender() {
        SimpleMailSender sender = new SimpleMailSender();
        sender.setHost(mailProperties.getHost());
        sender.setPort(mailProperties.getPort());
        sender.setUsername(mailProperties.getUsername());
        sender.setPassword(mailProperties.getPassword());
        return sender;
    }
}

Шаг 2: Создаём properties класс

// Файл: com/example/mail/MailProperties.java

import org.springframework.boot.context.properties.ConfigurationProperties;

@ConfigurationProperties(prefix = "app.mail")
public class MailProperties {
    private String host = "localhost";
    private int port = 25;
    private String username;
    private String password;
    
    // Getters and setters
    public String getHost() { return host; }
    public void setHost(String host) { this.host = host; }
    
    public int getPort() { return port; }
    public void setPort(int port) { this.port = port; }
    
    public String getUsername() { return username; }
    public void setUsername(String username) { this.username = username; }
    
    public String getPassword() { return password; }
    public void setPassword(String password) { this.password = password; }
}

Шаг 3: Регистрируем конфигурацию

# Файл: src/main/resources/META-INF/spring.factories

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.mail.MailAutoConfiguration

Шаг 4: Используем в приложении

// application.properties
app.mail.host=smtp.gmail.com
app.mail.port=587
app.mail.username=myemail@gmail.com
app.mail.password=mypassword
@Service
public class EmailService {
    private MailSender mailSender;
    
    public EmailService(MailSender mailSender) {
        this.mailSender = mailSender;  // Auto-configured!
    }
    
    public void sendEmail(String to, String subject, String body) {
        mailSender.send(to, subject, body);
    }
}

Как отключить определённую auto-configuration

Способ 1: application.properties

spring.autoconfigure.exclude=\
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration

Способ 2: Аннотация

@SpringBootApplication(
    exclude = {
        DataSourceAutoConfiguration.class,
        HibernateJpaAutoConfiguration.class
    }
)
public class MyApplication {
    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }
}

Процесс инициализации Spring Boot

public class MyApplication {
    public static void main(String[] args) {
        // 1. Создаётся SpringApplication
        SpringApplication app = new SpringApplication(MyApplication.class);
        
        // 2. Загружаются все enableAutoConfiguration из spring.factories
        // 3. Для каждой конфигурации проверяются условия (@ConditionalOn*)
        // 4. Если условия выполнены → конфигурация регистрируется
        // 5. Создаётся ApplicationContext
        // 6. В контексте создаются beans согласно конфигурациям
        // 7. Запускается приложение
        
        ApplicationContext context = app.run(args);
    }
}

Debugging auto-configurations

Способ 1: Логирование

# application.properties
logging.level.org.springframework.boot.autoconfigure=DEBUG
logging.level.org.springframework.boot.autoconfigure.condition=DEBUG

Способ 2: Actuator endpoint

# Зависит от spring-boot-starter-actuator

curl http://localhost:8080/actuator/conditions

# Выведет информацию о всех auto-configurations:
# - какие загружены
# - какие пропущены и почему

Способ 3: Программно

@Component
public class ConfigurationLogger {
    @Autowired
    private ConditionEvaluationReport conditionEvaluationReport;
    
    @PostConstruct
    public void logConfigurations() {
        conditionEvaluationReport.getMatched().forEach(record -> {
            System.out.println("Loaded: " + record.getSourceClassName());
        });
        
        conditionEvaluationReport.getUnmatched().forEach(record -> {
            System.out.println("Skipped: " + record.getSourceClassName());
            record.getConditions().forEach(condition -> {
                System.out.println("  Reason: " + condition.getCondition() + " - " + condition.getOutcome());
            });
        });
    }
}

Порядок загрузки beans

1. Spring Boot сканирует META-INF/spring.factories
   └─ Находит все EnableAutoConfiguration классы

2. Для каждого класса проверяет @ConditionalOn*
   ├─ @ConditionalOnClass — есть ли класс в classpath
   ├─ @ConditionalOnBean — есть ли bean в контексте
   ├─ @ConditionalOnProperty — есть ли свойство в конфиге
   └─ ... и т.д.

3. Если условия выполнены:
   ├─ Регистрирует конфигурацию
   ├─ Создаёт beans из этой конфигурации
   └─ Применяет @AutoConfigureAfter/@AutoConfigureBefore

4. Контекст готов к работе

Best Practices

  1. Используй @ConditionalOnMissingBean для гибкости:

    @Bean
    @ConditionalOnMissingBean
    public ObjectMapper objectMapper() { ... }
    // Пользователь может переопределить
    
  2. Документируй property конфигурации:

    @ConfigurationProperties(prefix = "app.mail")
    public class MailProperties {
        /**
         * SMTP host for sending emails
         */
        private String host;
    }
    
  3. Используй @ConditionalOnClass для опциональных зависимостей:

    @ConditionalOnClass(name = "javax.servlet.ServletContext")
    public class WebConfiguration { }
    
  4. Тестируй auto-configurations:

    @SpringBootTest
    class MailAutoConfigurationTest {
        @Test
        void shouldConfigureMailSender() {
            ApplicationContextRunner runner = new ApplicationContextRunner()
                .withConfiguration(AutoConfigurations.of(MailAutoConfiguration.class))
                .withPropertyValues("app.mail.host=smtp.example.com");
            
            runner.run(context -> {
                assertThat(context).hasSingleBean(MailSender.class);
            });
        }
    }
    

Вывод

Spring Boot подгружает модули через:

  1. spring.factories — регистр всех auto-configurations
  2. Условные аннотации (@ConditionalOn*) — определяют, когда загружать
  3. Порядок (@AutoConfigureAfter/Before) — контролирует последовательность
  4. Properties — параметризируют конфигурацию

Этот механизм делает Spring Boot "магическим" и позволяет добавлять зависимости, которые "просто работают" без явной конфигурации.