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

Как сделаешь, чтобы стартер не запустился при отсутствии логина, пароля и URL в application.properties

2.3 Middle🔥 121 комментариев
#Другое

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

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

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

Предотвращение запуска приложения при отсутствии обязательных параметров

Это важная задача валидации конфигурации на этапе старта приложения. Есть несколько способов решения в Spring Boot.

Способ 1: @ConfigurationProperties с валидацией (РЕКОМЕНДУЕТСЯ)

Это самый современный и чистый способ. Используем @ConfigurationProperties с @Validated и JSR-303 аннотациями:

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;

@Component
@ConfigurationProperties(prefix = "app.database")
public class DatabaseProperties {
    
    @NotBlank(message = "Database URL must not be blank")
    private String url;
    
    @NotBlank(message = "Database username must not be blank")
    private String login;
    
    @NotBlank(message = "Database password must not be blank")
    private String password;
    
    public DatabaseProperties() {}
    
    // Getters
    public String getUrl() { return url; }
    public String getLogin() { return login; }
    public String getPassword() { return password; }
    
    // Setters
    public void setUrl(String url) { this.url = url; }
    public void setLogin(String login) { this.login = login; }
    public void setPassword(String password) { this.password = password; }
}

В application.properties:

app.database.url=jdbc:mysql://localhost:3306/mydb
app.database.login=root
app.database.password=secret

Почему это работает: Spring автоматически валидирует properties при создании бина. Если какое-то поле не заполнено или не соответствует условиям, приложение не запустится с ошибкой BindValidationException.

Способ 2: Проверка через @Bean с @Conditional

Для более сложной логики можно использовать условное создание beans:

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

@Configuration
public class DatabaseConfig {
    
    @Bean
    @ConditionalOnProperty(
        name = "app.database.url",
        name = "app.database.login",
        name = "app.database.password",
        havingValue = "true" // все три должны быть присутствуют
    )
    public DataSource dataSource(DatabaseProperties props) {
        // Создание DataSource только если все параметры есть
        return new DataSourceBuilder()
            .url(props.getUrl())
            .username(props.getLogin())
            .password(props.getPassword())
            .build();
    }
}

Способ 3: ApplicationListener для проверки при старте

Проверка конфигурации при событии ContextRefreshedEvent:

import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;
import org.springframework.boot.SpringApplication;
import org.springframework.context.ApplicationContext;

@Component
public class ConfigurationValidator implements ApplicationListener<ContextRefreshedEvent> {
    
    private final Environment env;
    
    public ConfigurationValidator(Environment env) {
        this.env = env;
    }
    
    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        validateDatabaseConfiguration();
    }
    
    private void validateDatabaseConfiguration() {
        String url = env.getProperty("app.database.url");
        String login = env.getProperty("app.database.login");
        String password = env.getProperty("app.database.password");
        
        if (url == null || url.isBlank() ||
            login == null || login.isBlank() ||
            password == null || password.isBlank()) {
            
            throw new IllegalStateException(
                "Missing required database configuration: " +
                "app.database.url, app.database.login, app.database.password"
            );
        }
    }
}

Способ 4: PostConstruct проверка в компоненте

Проверка сразу после создания бина:

import jakarta.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

@Service
public class DatabaseService {
    
    @Value("${app.database.url:}")
    private String url;
    
    @Value("${app.database.login:}")
    private String login;
    
    @Value("${app.database.password:}")
    private String password;
    
    @PostConstruct
    public void validateConfiguration() {
        if (url.isBlank() || login.isBlank() || password.isBlank()) {
            throw new IllegalArgumentException(
                "Database configuration is incomplete. Required: " +
                "app.database.url, app.database.login, app.database.password"
            );
        }
    }
}

Способ 5: Custom Starter с автоконфигурацией

Для переиспользуемого решения создайте автоконфигурацию:

import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;

@AutoConfiguration
@EnableConfigurationProperties(DatabaseProperties.class)
public class DatabaseAutoConfiguration {
    
    @Bean
    public DatabaseConfigurationValidator databaseValidator(DatabaseProperties props) {
        return new DatabaseConfigurationValidator(props);
    }
}

// Сам валидатор
@Component
public class DatabaseConfigurationValidator {
    
    public DatabaseConfigurationValidator(DatabaseProperties props) {
        validateProperties(props);
    }
    
    private void validateProperties(DatabaseProperties props) {
        if (props.getUrl() == null || props.getUrl().isBlank()) {
            throw new IllegalStateException("app.database.url is required");
        }
        if (props.getLogin() == null || props.getLogin().isBlank()) {
            throw new IllegalStateException("app.database.login is required");
        }
        if (props.getPassword() == null || props.getPassword().isBlank()) {
            throw new IllegalStateException("app.database.password is required");
        }
    }
}

Сравнение подходов

ПодходПлюсыМинусыКогда использовать
@ConfigurationPropertiesСтандартно, встроено в Spring, типизированоТребует JSR-303 зависимостьВСЕГДА - это best practice
@ConditionalOnPropertyГибко, можно применять к beansСложнее для отладкиДля условного создания beans
ApplicationListenerПолный контроль, логированиеVerbose кодКогда нужна сложная логика
@PostConstructПросто, локально для сервисаНет早预 проверкиДля простых случаев
Custom StarterПереиспользуемо, чистое разделениеОверхед для маленьких проектовДля библиотек и starter'ов

Пример полного решения (РЕКОМЕНДУЕТСЯ)

// 1. Properties класс
@Component
@ConfigurationProperties(prefix = "app.database")
@Validated
public class DatabaseProperties {
    @NotBlank private String url;
    @NotBlank private String login;
    @NotBlank private String password;
    // getters/setters
}

// 2. application.properties
app.database.url=jdbc:mysql://localhost:3306/mydb
app.database.login=root
app.database.password=secret

// 3. Конфиг для DataSource
@Configuration
public class DatabaseConfiguration {
    @Bean
    public DataSource dataSource(DatabaseProperties props) {
        return DataSourceBuilder.create()
            .url(props.getUrl())
            .username(props.getLogin())
            .password(props.getPassword())
            .build();
    }
}

При отсутствии любого из параметров приложение выдаст:

Parameter 0 of constructor in ... required a bean of type ... that could not be found
Bound validation error in ...

И приложение не запустится, что именно требуется по задаче.