Перехватчик ответов JMS Spring Messaging

У меня есть метод @JmsListener, который получает параметр и возвращает экземпляр объекта, и все это работает с XML и маршалингом JAXB.

@JmsListener(
    containerFactory = ...,
    destination = ...,
    selector = ...
)
public RunReport.Response run(RunReport runReport) throws Exception
{
    // ...

    RunReport.Response response = new RunReport.Response();
    return response;
}

Это работает так, как я хочу, возвращая RunReport.Response вместо Message<RunReport.Response>.

Но я хочу внедрить заголовки JMS для ответа для всех моих методов JmsListener, т.е. я хочу сделать это в «промежуточном программном обеспечении» (настройка в моей конфигурации).

Какой путь я должен пройти, чтобы это сделать? Кажется, классы поддержки Spring JmsListener не настраиваются на этот уровень.

Добавьте MessagePostProcessor к заводским настройкам вашего слушателя. Таким образом, вы можете добавить все, что захотите.

M. Deinum 28.06.2018 20:26

Можете показать какой-нибудь отрывок? Я уже пробовал это, но у меня было много проблем с классами поддержки JmsListener.

Adriano dos Santos Fernandes 28.06.2018 21:29

Я привык к Rabbit и ошибочно полагал, что вы можете использовать тот же подход с JMS, но вы не можете. Что вы можете сделать, так это создать MessageConverter, который будет делать то, что вы хотите, который будет автоматически подключен ко всем вашим слушателям jms для преобразования ответа. Я предполагаю, что вы уже настроили один (я думаю, конвертер сортировки). Вы можете обернуть это в другой, который добавляет заголовки к сообщениям.

M. Deinum 28.06.2018 21:59
0
3
1 456
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вот такой:

/**
 * @see AbstractMessageListenerContainer#setMessageConverter(MessageConverter)
 */
public void setMessageConverter(MessageConverter messageConverter) {
    this.messageConverter = messageConverter;
}

На AbstractJmsListenerContainerFactory можете предоставить. На самом деле вам нужно предоставить такой @Bean только в контексте приложения, поскольку вы имеете дело с Spring Boot.

Этот вызывается из AbstractAdaptableMessageListener:

/**
 * Build a JMS message to be sent as response based on the given result object.
 * @param session the JMS Session to operate on
 * @param result the content of the message, as returned from the listener method
 * @return the JMS {@code Message} (never {@code null})
 * @throws JMSException if thrown by JMS API methods
 * @see #setMessageConverter
 */
protected Message buildMessage(Session session, Object result) throws JMSException {

Итак, это действительно место, где вы можете создать свой собственный JMS Message и установить его свойства и заголовки.

ОБНОВИТЬ

Я не знаю, что мне не хватает в ваших требованиях, но вот как я это вижу:

@SpringBootApplication
public class So51088580Application {

    public static void main(String[] args) {
        SpringApplication.run(So51088580Application.class, args);
    }

    @Bean
    public MessageConverter messageConverter() {
        return new SimpleMessageConverter() {

            @Override
            public Message toMessage(Object object, Session session) throws JMSException, MessageConversionException {
                Message message = super.toMessage(object, session);
                message.setStringProperty("myProp", "bar");
                return message;
            }

        };
    }

    @JmsListener(destination = "foo")
    public String jmsHandle(String payload) {
        return payload.toUpperCase();
    }

}

И тест-кейс по этому поводу:

@RunWith(SpringRunner.class)
@SpringBootTest
public class So51088580ApplicationTests {

    @Autowired
    private JmsTemplate jmsTemplate;

    @Test
    public void testReplyWithProperty() throws JMSException {
        Message message = this.jmsTemplate.sendAndReceive("foo", session -> session.createTextMessage("foo"));

        assertThat(message).isInstanceOf(TextMessage.class);
        TextMessage textMessage = (TextMessage) message;
        assertThat(textMessage.getText()).isEqualTo("FOO");
        assertThat(textMessage.getStringProperty("myProp")).isEqualTo("bar");
    }

}

Этот экземпляр создается с помощью new MessagingMessageListenerAdapter() внутри MethodJmsListenerEndpoint.createMessageListenerInstance. Вот почему я говорю, что сложно использовать вместе с @JmsListener. В этом контексте это не заменяемый компонент.

Adriano dos Santos Fernandes 28.06.2018 21:48

Правильно, этот createMessageListenerInstance() имеет код для распространения MessageConverter с предоставленного MessageListenerContainer на созданный MessagingMessageListenerAdapter.

Artem Bilan 28.06.2018 21:51

Фактически вы можете использовать MessageConverter, поскольку он создает сообщение, включая и позволяет вам установить заголовок. Вы можете создать конвертер сообщений добавления заголовков, который обертывает фактический конвертер и после вызова делегата добавляет заголовки.

M. Deinum 28.06.2018 21:57

См. ОБНОВЛЕНИЕ в моем ответе, пожалуйста.

Artem Bilan 28.06.2018 22:06

В моем случае (с использованием JAXB) я переопределил toMessage конвертера org.springframework.jms.support.converter.MarshallingMessage‌, и это сработало. Спасибо.

Adriano dos Santos Fernandes 29.06.2018 15:46

Другие вопросы по теме