в Spring amqp как инкапсулировать RabbitListener на высоком уровне

Я использую spring amqp в своем проекте, и я использую реализации ChannelAwareMessageListener для повторной отправки и обработки исключения, чтобы сделать слушателя кролика более стабильным:

   public abstract class AbstractMessageListener implements ChannelAwareMessageListener {


    @Autowired
    private Jackson2JsonMessageConverter messageConverter;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    /** where comsumer really do biz */
    public abstract void receiveMessage(Message message, MessageConverter messageConverter);

    @Override
    public void onMessage(Message message, Channel channel) throws Exception {
        MessageProperties messageProperties = message.getMessageProperties();
        Long deliveryTag = messageProperties.getDeliveryTag();
        Long consumerCount = redisTemplate.opsForHash().increment(MQConstants.MQ_CONSUMER_RETRY_COUNT_KEY,
                messageProperties.getMessageId(), 1);
        try {
            receiveMessage(message, messageConverter);
            channel.basicAck(deliveryTag, false);             
            redisTemplate.opsForHash().delete(MQConstants.MQ_CONSUMER_RETRY_COUNT_KEY,
                    messageProperties.getMessageId());
        } catch (Exception e) {

            if (consumerCount >= MQConstants.MAX_CONSUMER_COUNT) {               
                channel.basicReject(deliveryTag, false);
            } else {               
                Thread.sleep((long) (Math.pow(MQConstants.BASE_NUM, consumerCount)*1000));
                channel.basicNack(deliveryTag, false, true);
            }
        }
    }

тогда мы можем получить, расширив наш AbstractMessageListener следующим образом:

public class BizMessageListener extends AbstractMessageListener  {

    Logger logger = LoggerFactory.getLogger(getClass());

    @Override
    public void receiveMessage(Message message, MessageConverter messageConverter) {
        //do our own biz
    }
}

но однажды мой босс сказал, что это слишком. Вторжение, вы вместо этого используете аннотацию ,, поэтому я нашел что-то вроде этого: Spring RabbitMQ - использование ручного подтверждения канала в службе с конфигурацией @RabbitListener

где я могу использовать аннотацию как

@RabbitListener(queues = "so38728668")
        public void receive(String payload, Channel channel, @Header(AmqpHeaders.DELIVERY_TAG) long tag)
                throws IOException {

но как я могу инкапсулировать @RabbitListener на высоком уровне, чтобы объединить мой собственный код повторной отправки сообщения в моем первом образце кода, например, есть аннотация как RabbitResenderListener

 @RabbitResenderListener(queues = "so38728668")
            public void receive(Message msg)
                    throws IOException {
 // just do biz 
}

эта аннотация дает методу возможность повторной отправки сообщения и возможности обработки ошибок, так что метод выполняет только biz. спасибо


person vvsueprman    schedule 23.01.2018    source источник


Ответы (1)


Не уверен, чего вы от нас ждете, но мне кажется, что аннотации не предназначены для расширений и извлечения абстракций, как мы можем делать с классами.

В любом случае я могу поделиться какой-то идеей, вы можете попробовать.

Есть аннотация уровня метода @RabbitHandler. Таким образом, вы можете пометить этим метод в суперклассе и выполнить всю логику инфраструктуры. Целевая реализация должна быть отмечена конкретным @RabbitListener в классе, чтобы получить требуемую queues конфигурацию. Метод @RabbitHandler вызовет полиморфный метод от наследника.

Это звучит разумно?

person Artem Bilan    schedule 23.01.2018
comment
Да, это то, что я хочу сделать, вместо этого я не хочу создавать суперкласс, потому что, если я создам суперкласс, любой слушатель, который мы напишем, должен расширить этот суперкласс, так как он называется навязчивым. Я хочу написать класс, расширяющий некоторый исходный код amqp, и написать логику моей инфраструктуры в этом классе. тогда любой класс с @RabbitListener может выполнять только бизнес-логику, что означает ненавязчивость. - person vvsueprman; 24.01.2018
comment
Было бы здорово увидеть какой-нибудь PoC, но в любом случае @RabbitListener уже является источником AMQP, он очень привязан к контракту метода и очень близок к контейнеру слушателя. Возможно, вам потребуется изучить Spring Integration для следующего уровня абстракции между сервисами: projects.spring. io / весенняя интеграция - person Artem Bilan; 24.01.2018
comment
Привет, я нашел класс MessagingMessageListenerAdapter.java в исходном коде amqp, думаю, может быть, я смогу переопределить метод onMessage () и добавить свою собственную логику инфраструктуры. работает ли это? И как это сделать, сможет ли Spring распознать мой новый класс, расширив MessagingMessageListenerAdapter? или есть другие способы перекрыть исходный код amqp? Спасибо - person vvsueprman; 25.01.2018
comment
Нет, ты не можешь этого сделать. Это очень специфический код, связанный со всей обработкой аннотаций. Однако вы можете рассмотреть возможность реализации некоторых советов AOP, которые могут применяться к выбранным бизнес-сервисам и могут вызывать соответствующую логику инфраструктуры. У @RabbitListener есть опция containerFactory(), где этот AbstractRabbitListenerContainerFactory может поставляться с adviceChain. - person Artem Bilan; 25.01.2018