Affects: \Spring 6.0.x / Spring Boot 3.1.x
I am trying to provide a custom implementation of a MessagingMessageListenerAdapter for each created JmsListenerEndpoint. The reason i would like to do this is that i want to use Micrometer/Opentelemetry tracing on incoming and outgoing JMS messages. Since JMS instrumentation is currently not implemented in Micrometer and i am using custom headers for communicating with the remote system anyways, i need to open a tracing scope before calling onMessage on the MessagingMessageListenerAdapter and close it afterwards. I would also like to write a custom tracing propagation header to the JMS result message.
Looking at the code, it seems like i have to override createMethodJmsListenerEndpoint() in JmsListenerAnnotationBeanPostProcessor in order to return a custom MethodJmsListenerEndpoint with an overridden createMessageListenerInstance() method, returning my customized MessagingMessageListenerAdapter:
- JmsListenerAnnotationBeanPostProcessor
- MethodJmsListenerEndpoint
Simply providing a JmsListenerAnnotationBeanPostProcessor as a bean works, but now there seem to be two competing instances of said PostProcessor, causing all JmsListeners to be registered twice. This causes a conflict in the EndpointRegistry, since now both PostProcessors try registering these listeners on the same registry.
Looking at the JmsListenerAnnotationBeanPostProcessor provided by Spring, it is annotated with @Bean(name = JmsListenerConfigUtils.JMS_LISTENER_ANNOTATION_PROCESSOR_BEAN_NAME) and @Role(BeanDefinition.ROLE_INFRASTRUCTURE). Providing a PostProcessor using these annotations, i would now have to also provide a bean named org.springframework.jms.config.internalJmsListenerEndpointRegistry. I would like avoiding creating tons of other internal* beans (unless i have to).
I also tried registering my bean together with using the @EnableJms annotation. This now leads to a dependency conflict, since the presence of @EnableJms automagically leads to the registration of another bean with the JMS_LISTENER_ANNOTATION_PROCESSOR_BEAN_NAME.
Unless i am missing something, i think there is some room for improvement here. One option is that the return value of createMethodJmsListenerEndpoint() and createMessageListenerInstance() should not depend on a fixed type of MessageListener/Endpoint, but on a value provided by some Factory for the given objects. Another option would be to scan for custom Beans of type JmsListenerAnnotationBeanPostProcessor when @EnableJms is present. Only if none was provided, the default implementation should be used.
In my personal opinion, providing both values based on Factories would be the most developer-friendly solution.
Sorry if i am thinking too complicated here or if i missed something in the docs!
Comment From: snicoll
JmsListenerAnnotationBeanPostProcessor is definitely not meant to be exposed in application code. The bean name having internal in its name is actually sending a strong signal in that direction.
Since JMS instrumentation is currently not implemented
It is implemented now.
I think we need to take a step back. Please review the JMS instrumentation supported added in spring framework and we can take it from there. Advanced customizations, especially on features the framework should support are not a good idea as it increates the maintenance cost on your side.
If after reviewed the latest state you still need an hook point, let's discuss that please, rather than what happens when you try to do it yourself.