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.
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
// connectionFactoryBecause @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.
Reference
Source code: https://github.com/lltx/spring-boot-course/tree/master/v2.3/refresh-scope-bug
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Java Architecture Diary
Committed to sharing original, high‑quality technical articles; no fluff or promotional content.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
