In Spring Cloud architecture projects, the configuration center is mainly used to provide distributed configuration management, with an important annotation: @refreshScope, which can be added to the required classes if the configuration needs to be dynamically refreshed in the code. This article to share the author met with @ ConditionalOnSingleCandidate notes the problem of conflict
The problem background
The project also introduced RabbitMQ and added @refreshScope when customizing the connectionFactory
@Bean @RefreshScope public CachingConnectionFactory connectionFactory() { CachingConnectionFactory connectionFactory = new CachingConnectionFactory(); 172.17.0.111 connectionFactory. SetAddresses (" "); connectionFactory.setUsername("guest"); connectionFactory.setPassword("guest"); connectionFactory.setVirtualHost("/"); return connectionFactory; }Copy the code
The system fails 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.
Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
Copy the code
screening
-
- By default spring-boot-starter-AMqp will inject the rabbitTemplate implementation by default
RabbitAutoConfiguration#rabbitTemplate
@Bean
@ConditionalOnSingleCandidate(ConnectionFactory.class)
@ConditionalOnMissingBean(RabbitOperations.class)
public RabbitTemplate rabbitTemplate(RabbitTemplateConfigurer configurer, ConnectionFactory connectionFactory) {
RabbitTemplate template = new RabbitTemplate();
configurer.configure(template, connectionFactory);
return template;
}Copy the code
-
- Start Spring Boot. Start the debugger logs to view the injection information
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)Copy the code
Prompt ConditionalOnSingleCandidate annotation method can’t find the only ConnectionFactory
-
- Beans that use the @refreshScope annotation are also generated by default
scopedTarget.beanName
The bean
- Beans that use the @refreshScope annotation are also generated by default
@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);
}
scopedTarget.connectionFactory
connectionFactoryCopy the code
-
- Because ConditionalOnSingleCandidate establishment is the condition of only one of this type of bean so the default RabbitTemplate cannot injection
Bean is common ConditionalOnSingleCandidate annotations
-
- Cannot add @refreshScope to the custom DataSource using JdbcTemplate
@ConditionalOnSingleCandidate(DataSource.class)
public class JdbcTemplateAutoConfiguration {}Copy the code
-
- MailSenderValidator Could not add @refreshScope to the mail send validator
@Configuration(proxyBeanMethods = false)
@AutoConfigureAfter(MailSenderAutoConfiguration.class)
@ConditionalOnProperty(prefix = "spring.mail", value = "test-connection")
@ConditionalOnSingleCandidate(JavaMailSenderImpl.class)
public class MailSenderValidatorAutoConfiguration {}Copy the code
-
- Because there are many beans involved by default, these should be avoided when using RefreshScope
- Supporting source: https://github.com/lltx/spring-boot-course/tree/master/v2.3/refresh-scope-bug