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

Как избежать конфликта при наличии двух бинов одного типа в Spring?

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

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

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

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

Избегание конфликтов при наличии двух бинов одного типа в Spring

Это частая проблема при разработке на Spring, когда контейнер не может определить, какой из нескольких бинов одного типа использовать при внедрении зависимостей. Существует несколько проверенных подходов для её решения.

1. Аннотация @Qualifier

Это самый популярный и чистый способ. Используется для явного указания имени бина:

@Configuration
public class DataSourceConfig {
    @Bean("primaryDb")
    public DataSource primaryDataSource() {
        return new DataSource();
    }
    
    @Bean("secondaryDb")
    public DataSource secondaryDataSource() {
        return new DataSource();
    }
}

@Service
public class UserService {
    private final DataSource primaryDb;
    private final DataSource secondaryDb;
    
    public UserService(@Qualifier("primaryDb") DataSource primaryDb,
                       @Qualifier("secondaryDb") DataSource secondaryDb) {
        this.primaryDb = primaryDb;
        this.secondaryDb = secondaryDb;
    }
}

2. Аннотация @Primary

Указывает, какой бин использовать по умолчанию при отсутствии @Qualifier:

@Configuration
public class DataSourceConfig {
    @Bean
    @Primary
    public DataSource primaryDataSource() {
        return new DataSource();
    }
    
    @Bean
    public DataSource secondaryDataSource() {
        return new DataSource();
    }
}

@Service
public class UserService {
    private final DataSource dataSource; // будет использован primaryDataSource
    
    public UserService(DataSource dataSource) {
        this.dataSource = dataSource;
    }
}

3. Внедрение нескольких бинов в коллекцию

Полезно, когда нужны все реализации:

@Configuration
public class DatabaseConfig {
    @Bean("postgres")
    public Database postgresDb() {
        return new PostgresDatabase();
    }
    
    @Bean("mysql")
    public Database mysqlDb() {
        return new MySQLDatabase();
    }
}

@Service
public class DataService {
    private final List<Database> databases;
    private final Map<String, Database> databaseMap;
    
    public DataService(List<Database> databases, 
                      Map<String, Database> databaseMap) {
        this.databases = databases; // будут оба бина
        this.databaseMap = databaseMap; // {postgres=..., mysql=...}
    }
}

4. Кастомная аннотация

Для сложных сценариев можно создать свою аннотацию:

@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface PrimaryDatabase {}

@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface CacheDatabase {}

@Configuration
public class DbConfig {
    @Bean
    @PrimaryDatabase
    public DataSource primaryDb() {
        return new DataSource();
    }
    
    @Bean
    @CacheDatabase
    public DataSource cacheDb() {
        return new DataSource();
    }
}

@Service
public class OrderService {
    public OrderService(@PrimaryDatabase DataSource db,
                       @CacheDatabase DataSource cache) {
        // красивое и явное указание
    }
}

5. Профили Spring

Для различных окружений:

@Configuration
public class DatabaseConfig {
    @Bean
    @Profile("prod")
    public DataSource prodDataSource() {
        return new ProdDataSource();
    }
    
    @Bean
    @Profile("dev")
    public DataSource devDataSource() {
        return new DevDataSource();
    }
}

Рекомендации

  1. Используй @Qualifier для явности — всегда понятно, какой бин используется
  2. @Primary подходит только для одного "основного" бина
  3. Избегай неявных зависимостей и магии — явность лучше
  4. Назови бины осмысленноprimaryDatabase, а не db1
  5. Документируй причину наличия нескольких бинов в Javadoc

Правильный выбор подхода зависит от контекста: для временно-пространственного разделения данных — @Qualifier, для разных профилей — @Profile, для коллекций — Map/List.

Как избежать конфликта при наличии двух бинов одного типа в Spring? | PrepBro