I have a strange situation that I don't understand. I would like to decide in a bean, should I enable or disable the SQS listener. So I've created a config class with a definition:
@Bean
MyListener createListener(Features f){
return f.shouldListen() ? new RealListener() : new MockListener();
}
As you can see, I have such an inheritance:
interface MyListener{}
class RealListener implements MyListener{
@SqsListener(...)
list handleMessage(SqsMessage message){
...
}
}
class MockListener implements MyListener{}
Now, the funny part:
It sometimes works.
After few restarts of the application, the handleMessage()
method is called but in most cases it isn't without any exception. The queue is created, all permissions are in place.
To make it working I need to return RealListener
from createListener()
method or move @SqsListener
annotation to a method in the MyListener
interface. Both are not options for me, because I don't want to call AWS, when the mock is enabled.
I've tried with conditional bean creation but as Features
depends on a DB (indirect entityManager dependency, to be more precise), I can't make it working. I've tried with abstract class instead of interface, but without luck. I've tried to register the RealListener
bean in the BeanFactoryPostProcessor
but this also doesn't work (same entityManager
dependency issue). I've tried to move the annotation to the interface and use @ConditionalOnBean
with @Primary
to create an empty AmazonSqsClient
when the mock is enabled, but it doesn't work.
I could understand that it doesn't work, because the bean has to be created for a type with the method annotated with @SqsListener
(not with it's supperclass/interface type), but I have three such beans and a lottery - sometimes all work, sometimes one or two but sometimes none of those.
Do you have any suggestions?
Well... I've found the issue but it still would be nice, to know, what has happened.
So... There is a class
QueueMessageHandler
usingdetectHandlerMethods(...)
method from the superclassAbstractMethodMessageHandler
. This method usesMethodIntrospector.selectMethods()
to select methods to scan. This class takes into consideration methods annotated with@SqsListener
when there is@EnableSqs
in some configuration class. The problem is, in my project the@EnableSqs
annotation is located in some file - not the file withcreateListener(...)
method and not the main class of the Spring Boot application. That means, the class with@EnableSqs
can be loaded before or afterMethodIntrospector.selectMethods()
.The output is:
@EnableSqs
to the main class of the project