Good night.
I have a library that extends Spring AMQP and changes the default Autoconfiguration file (I will open source it).
But when I migrate to Spring Boot 2.1.4, the method that is responsible to change the RabbitListenerAnnotationBeanPostProcessor behavior simply stop to be called.
@Primary
@Bean(name = RabbitListenerConfigUtils.RABBIT_LISTENER_ANNOTATION_PROCESSOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_APPLICATION)
@DependsOn(RabbitConstants.CONNECTION_FACTORY_BEAN_NAME)
public RabbitListenerAnnotationBeanPostProcessor rabbitListenerAnnotationProcessor() {
return new NewRabbitListenerAnnotationBeanPostProcessor();
}
This method belongs to a class that I defined to be the default Autoconfiguration file.
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.amqp.NewRabbitAutoConfiguration
@Configuration
@ConditionalOnClass({ RabbitTemplate.class, Channel.class })
@EnableConfigurationProperties({ RabbitProperties.class, RabbitCustomPropertiesMap.class })
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@Import(RabbitAnnotationDrivenConfiguration.class)
public class NewRabbitAutoConfiguration {
...
}
So, if I can't call my NewRabbitListenerAnnotationBeanPostProcessor I will be a problem because I have some treats for the attribute containerFactory of RabbitListener annotation.
I think the problem is: RabbitListenerAnnotationBeanPostProcessor is executing before the new AutoConfiguration class (NewRabbitAutoConfiguration)
I tried to annotate the bean of my Listener with @ConditionalOnBean(NewRabbitAutoConfiguration.class), but the result was very strange, Spring called all methods of the NewRabbitAutoConfiguration but not call the rabbitListenerAnnotationProcessor method (and the bean RabbitConstants.CONNECTION_FACTORY_BEAN_NAME) was created.
I've created a repo to simulate the problem: https://github.com/juliofalbo/spring-2.1.4-bug-override-bean-post-processor
Note: If we change the version of Spring Boot to 2.1.3.RELEASE, works fine!
Can someone help me with this issue?
I'm not sure what exactly has changed between 2.1.3 and 2.1.4 but your configuration looks quite unusual and I wouldn't recommend taking such an approach.
Specifically:
org.springframework.boot.autoconfigure.amqp in an open source project. The org.springframework package is reserved for official Spring projects.spring.main.allow-bean-definition-overriding=true is not recommended@AutoConfigureOrder of HIGHEST is likely going to cause problemsrabbitListenerAnnotationProcessor method might cause some initialization issues since it's a bean post processor that depends on a connection factory.Instead I think it might be better to structure your configuration like this:
@Configuration
@ConditionalOnClass({ RabbitTemplate.class, Channel.class })
@AutoConfigureBefore(RabbitAutoConfiguration.class)
@Import({NewRabbitAutoConfiguration.RabbitPostProcessorConfiguration.class, RabbitAnnotationDrivenConfiguration.EnableRabbitConfiguration.class})
public class NewRabbitAutoConfiguration {
@Configuration
static class RabbitPostProcessorConfiguration {
@Bean(name = RabbitListenerConfigUtils.RABBIT_LISTENER_ANNOTATION_PROCESSOR_BEAN_NAME)
public static RabbitListenerAnnotationBeanPostProcessor rabbitListenerAnnotationProcessor() {
return new NewRabbitListenerAnnotationBeanPostProcessor();
}
}
@Configuration
@EnableRabbit
static class EnableRabbitConfiguration {
@Bean(name = RabbitListenerConfigUtils.RABBIT_LISTENER_ANNOTATION_PROCESSOR_BEAN_NAME)
public static RabbitListenerAnnotationBeanPostProcessor rabbitListenerAnnotationProcessor() {
return new NewRabbitListenerAnnotationBeanPostProcessor();
}
}
}
This will create a configuration that's ordered to run before ours (because of @AutoConfigureBefore(RabbitAutoConfiguration.class)). It will import a couple of configuration in a specific order. The first will register your post processor and the second will enable rabbit.
The @EnableRabbit annotation triggers RabbitBootstrapConfiguration but this won't replace your post processor because it has an explicit check. When our auto-configuration runs it backs-off because it already finds a post processor.
Hi Phil!
Thank you very much for your quick help!
Perfect, I'm sorry about the package, I didn't know about this info, but one question.
How can I access the RabbitAnnotationDrivenConfiguration.class in another package? This class is not public. :(
I don't think you need to so do. Phil is proposing that you have your own EnableRabbitConfiguration so you can drop the import of RabbitAnnotationDrivenConfiguration.EnableRabbitConfiguration.class.
Perfect Andy!
Thank you very much everyone!
Hi, I have another question.
Phil said that requiring users to have spring.main.allow-bean-definition-overriding=true is not recommended, and I agree 100%, but there is another way to avoid this?
Thank you very much all support!
@juliofalbo I don't think it's needed with the sample I gave above because rather than replacing beans, you version registers them first and the other configurations just back off.
Most helpful comment
I'm not sure what exactly has changed between 2.1.3 and 2.1.4 but your configuration looks quite unusual and I wouldn't recommend taking such an approach.
Specifically:
org.springframework.boot.autoconfigure.amqpin an open source project. Theorg.springframeworkpackage is reserved for official Spring projects.spring.main.allow-bean-definition-overriding=trueis not recommended@AutoConfigureOrderofHIGHESTis likely going to cause problemsrabbitListenerAnnotationProcessormethod might cause some initialization issues since it's a bean post processor that depends on a connection factory.Instead I think it might be better to structure your configuration like this:
This will create a configuration that's ordered to run before ours (because of
@AutoConfigureBefore(RabbitAutoConfiguration.class)). It will import a couple of configuration in a specific order. The first will register your post processor and the second will enable rabbit.The
@EnableRabbitannotation triggersRabbitBootstrapConfigurationbut this won't replace your post processor because it has an explicit check. When our auto-configuration runs it backs-off because it already finds a post processor.