Backend Development 5 min read

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:

<code>@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;
}
</code>

The system then reported an error unable to inject

RabbitTemplate

:

<code>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.
</code>

Investigation

By default,

spring-boot-starter-amqp

provides a

RabbitTemplate

bean via

RabbitAutoConfiguration

.

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

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

.

<code>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)
</code>

Beans annotated with @RefreshScope generate an additional bean named

scopedTarget.&lt;beanName&gt;

. Therefore, after adding @RefreshScope, there are two

ConnectionFactory

beans, breaking the

@ConditionalOnSingleCandidate

condition.

<code>@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
</code>

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.

<code>@ConditionalOnSingleCandidate(DataSource.class)
public class JdbcTemplateAutoConfiguration {}
</code>

MailSenderValidator cannot be refreshed with @RefreshScope.

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

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

Spring BootRabbitMQRefreshScopeBean 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

login 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.