Fixing @RefreshScope Conflict with @ConditionalOnSingleCandidate in Spring Boot

In Spring Cloud projects, adding @RefreshScope to a custom RabbitMQ ConnectionFactory can clash with @ConditionalOnSingleCandidate, preventing RabbitTemplate from being auto‑wired; this article explains the root cause, demonstrates how to diagnose the issue, and provides a solution to avoid such bean conflicts.

Java Architecture Diary
Java Architecture Diary
Java Architecture Diary
Fixing @RefreshScope Conflict with @ConditionalOnSingleCandidate in Spring Boot

In Spring Cloud applications, the configuration center provides distributed configuration management, and the @RefreshScope annotation enables dynamic refresh of beans. This article shares a problem where @RefreshScope conflicts with @ConditionalOnSingleCandidate, causing RabbitTemplate injection to fail.

Problem Background

When introducing RabbitMQ, a custom connectionFactory bean was mistakenly annotated with @RefreshScope:

@Bean
@RefreshScope
public CachingConnectionFactory connectionFactory() {
    CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
    connectionFactory.setAddresses("172.17.0.111");
    connectionFactory.setUsername("guest");
    connectionFactory.setPassword("guest");
    connectionFactory.setVirtualHost("/");
    return connectionFactory;
}

The system then reported an error unable to inject RabbitTemplate:

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'com.pig4cloud.course.refresh.bug.RefreshBugApplicationTest':
Unsatisfied dependency expressed through field 'rabbitTemplate'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException:
No qualifying bean of type 'org.springframework.amqp.rabbit.core.RabbitTemplate' available: expected at least 1 bean which qualifies as autowire candidate.

Investigation

By default, spring-boot-starter-amqp provides a RabbitTemplate bean via RabbitAutoConfiguration.

@Bean
@ConditionalOnSingleCandidate(ConnectionFactory.class)
@ConditionalOnMissingBean(RabbitOperations.class)
public RabbitTemplate rabbitTemplate(RabbitTemplateConfigurer configurer, ConnectionFactory connectionFactory) {
    RabbitTemplate template = new RabbitTemplate();
    configurer.configure(template, connectionFactory);
    return template;
}

Enabling Spring Boot startup debugger logs shows that the condition @ConditionalOnSingleCandidate does not match because multiple beans of type ConnectionFactory exist: connectionFactory and scopedTarget.connectionFactory.

RabbitAutoConfiguration.RabbitTemplateConfiguration#rabbitTemplate:
    Did not match:
        - @ConditionalOnSingleCandidate (types: org.springframework.amqp.rabbit.connection.ConnectionFactory; SearchStrategy: all)
        did not find a primary bean from beans 'connectionFactory', 'scopedTarget.connectionFactory' (OnBeanCondition)

Beans annotated with @RefreshScope generate an additional bean named scopedTarget.<beanName>. Therefore, after adding @RefreshScope, there are two ConnectionFactory beans, breaking the @ConditionalOnSingleCandidate condition.

@Autowired
private ApplicationContext context;

@Test
public void testRabbitTemplate() {
    String[] beanNames = context.getBeanNamesForType(ConnectionFactory.class);
    for (String beanName : beanNames) {
        System.out.println(beanName);
    }
    Assert.isTrue(beanNames.length == 2);
}

// Output shows:
// scopedTarget.connectionFactory
// connectionFactory

Because @ConditionalOnSingleCandidate requires a unique bean of the specified type, the default RabbitTemplate cannot be injected when the condition fails.

Common Beans Annotated with @ConditionalOnSingleCandidate

Adding @RefreshScope to a custom DataSource prevents JdbcTemplate auto‑configuration.

@ConditionalOnSingleCandidate(DataSource.class)
public class JdbcTemplateAutoConfiguration {}

MailSenderValidator cannot be refreshed with @RefreshScope.

@Configuration(proxyBeanMethods = false)
@AutoConfigureAfter(MailSenderAutoConfiguration.class)
@ConditionalOnProperty(prefix = "spring.mail", value = "test-connection")
@ConditionalOnSingleCandidate(JavaMailSenderImpl.class)
public class MailSenderValidatorAutoConfiguration {}

Since many default beans are guarded by @ConditionalOnSingleCandidate, using @RefreshScope on them should be avoided.

Therefore, when applying @RefreshScope, ensure that the bean does not participate in a @ConditionalOnSingleCandidate condition, or provide a primary bean to satisfy the condition.

Diagram illustrating bean conflict
Diagram illustrating bean conflict

Reference

Source code: https://github.com/lltx/spring-boot-course/tree/master/v2.3/refresh-scope-bug

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Spring BootRabbitMQ@RefreshScopeBean InjectionConditionalOnSingleCandidate
Java Architecture Diary
Written by

Java Architecture Diary

Committed to sharing original, high‑quality technical articles; no fluff or promotional content.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.