Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
# @Conditional в Spring
Назначение
@Conditional — это аннотация в Spring Framework, которая позволяет условно регистрировать beans только если выполнены определённые условия. Это мощный механизм для создания гибких и модульных приложений.
Основной синтаксис
@Conditional(MyCondition.class)
@Bean
public MyService myService() {
return new MyService();
}
Когда Spring инициализирует контекст, он проверяет класс условия (который реализует интерфейс Condition). Если метод matches() возвращает true, bean регистрируется. Если false, bean не создаётся.
Создание собственного условия
public class MySQLDatabaseCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
String dbType = context.getEnvironment().getProperty("db.type");
return "mysql".equalsIgnoreCase(dbType);
}
}
@Configuration
public class DatabaseConfiguration {
@Conditional(MySQLDatabaseCondition.class)
@Bean
public DataSource mysqlDataSource() {
System.out.println("Creating MySQL DataSource");
return new HikariDataSource();
}
}
Встроенные условия
@ConditionalOnProperty
Регистрирует bean если задана определённая property:
@ConditionalOnProperty(
name = "app.notifications.enabled",
havingValue = "true"
)
@Bean
public EmailNotificationService emailService() {
return new EmailNotificationService();
}
@ConditionalOnClass
Регистрирует bean если в classpath присутствует определённый класс:
@ConditionalOnClass(DataSource.class)
@Bean
public JdbcTemplate jdbcTemplate(DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
Это полезно в auto-configuration: если приложение использует JDBC, автоматически создаём JdbcTemplate.
@ConditionalOnMissingBean
Регистрирует bean только если в контексте нет другого bean того же типа:
@ConditionalOnMissingBean(CacheManager.class)
@Bean
public CacheManager defaultCacheManager() {
return new SimpleCacheManager();
}
@ConditionalOnBean
Регистрирует bean только если в контексте есть другой bean определённого типа:
@ConditionalOnBean(DataSource.class)
@Bean
public ConnectionPoolLogger connectionPoolLogger() {
return new ConnectionPoolLogger();
}
@ConditionalOnExpression
Регистрирует bean если выполнено SpEL выражение:
@ConditionalOnExpression("${feature.advanced.enabled:false} && ${feature.premium.enabled:false}")
@Bean
public AdvancedFeatureService advancedFeature() {
return new AdvancedFeatureService();
}
Практические примеры
Выбор реализации в зависимости от профиля
public class ProductionEmailCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
String[] profiles = context.getEnvironment().getActiveProfiles();
return Arrays.asList(profiles).contains("production");
}
}
@Configuration
public class EmailConfiguration {
@Conditional(ProductionEmailCondition.class)
@Bean
public EmailService productionEmailService() {
return new RealEmailService();
}
@ConditionalOnProperty(name = "app.profile", havingValue = "development")
@Bean
public EmailService developmentEmailService() {
return new MockEmailService();
}
}
Условная регистрация с проверкой класса
public class MongoDbCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
try {
Class.forName("com.mongodb.client.MongoClient");
return true;
} catch (ClassNotFoundException e) {
return false;
}
}
}
@Configuration
public class NoSQLConfiguration {
@Conditional(MongoDbCondition.class)
@Bean
public MongoTemplate mongoTemplate(MongoClient mongoClient) {
return new MongoTemplate(mongoClient, "mydb");
}
}
Комплексное условие
public class CacheCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
String cacheEnabled = context.getEnvironment().getProperty("cache.enabled");
String cacheType = context.getEnvironment().getProperty("cache.type");
return "true".equalsIgnoreCase(cacheEnabled) && cacheType != null;
}
}
@Configuration
public class CacheConfiguration {
@Conditional(CacheCondition.class)
@Bean
public CacheManager cacheManager(Environment env) {
String cacheType = env.getProperty("cache.type");
switch(cacheType) {
case "redis":
return new RedisCacheManager();
case "memcached":
return new MemcachedCacheManager();
default:
return new SimpleCacheManager();
}
}
}
Кейсы использования
Auto-configuration в стартерах
Spring Boot использует @Conditional для auto-configuration:
@Configuration
@ConditionalOnClass({ DataSource.class, JpaRepository.class })
@EnableJpaRepositories
public class JpaRepositoriesAutoConfiguration {
// ...
}
Feature flagging
@ConditionalOnProperty(
name = "feature.new-ui.enabled",
havingValue = "true"
)
@Bean
public UIService newUIService() {
return new ModernUIService();
}
Выбор реализации по платформе
public class WindowsCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
String os = System.getProperty("os.name").toLowerCase();
return os.contains("win");
}
}
@Configuration
public class PlatformConfiguration {
@Conditional(WindowsCondition.class)
@Bean
public FileSystemWatcher windowsWatcher() {
return new WindowsFileSystemWatcher();
}
}
Лучшие практики
- Делайте условия явными — название должно описывать условие
- Логируйте решения — добавьте логирование для отладки
- Используйте встроенные условия когда возможно — @ConditionalOnProperty, @ConditionalOnClass и т.д.
- Комбинируйте условия — несколько условий должны быть истинны одновременно
Резюме
@Conditional позволяет:
- Гибко конфигурировать приложение в зависимости от окружения
- Модульно организовать код
- Автоматически регистрировать beans на основе условий
- Условно включать/выключать функциональность
Это критически важно для написания гибких Spring приложений и создания стартеров, которые работают в разных окружениях.