2015-06-11 5 views
9

मैं बसंत बूट के साथ एक साधारण वसंत बूट ऐप बनाने की कोशिश कर रहा हूं जो एक खरगोश एक्सचेंज/कतार में संदेश "उत्पादन" करता है और एक और नमूना वसंत बूट ऐप जो इन संदेशों को "उपभोग" करता है। तो मेरे पास दो ऐप्स हैं (या यदि आप चाहें तो माइक्रोसाइसेस)। 1) "निर्माता" माइक्रोस्कोस 2) "उपभोक्ता" माइक्रोस्कोसवसंत बूट rabbitmq मैपिंग जैकसन 2 मैसेज कनवर्टर कस्टम ऑब्जेक्ट रूपांतरण

"निर्माता" में 2 डोमेन ऑब्जेक्ट्स हैं। फू और बार जिसे जेसन में परिवर्तित किया जाना चाहिए और खरगोश को भेजना चाहिए। "उपभोक्ता" को क्रमशः डोमेन फू और बार में जेसन संदेश प्राप्त और परिवर्तित करना चाहिए। किसी कारण से मैं यह सरल कार्य नहीं कर सकता। इसके बारे में बहुत कुछ उदाहरण नहीं हैं। संदेश कनवर्टर मैं org.springframework.messaging.converter.MappingJackson2MessageConverter

यहाँ का उपयोग करने के लिए क्या मैं अब तक है:

निर्माता MICROSERVICE

package demo.producer; 

import org.springframework.amqp.core.Binding; 
import org.springframework.amqp.core.BindingBuilder; 
import org.springframework.amqp.core.Queue; 
import org.springframework.amqp.core.TopicExchange; 
import org.springframework.amqp.rabbit.core.RabbitMessagingTemplate; 
import org.springframework.beans.factory.annotation.Autowired; 
import org.springframework.boot.CommandLineRunner; 
import org.springframework.boot.SpringApplication; 
import org.springframework.boot.autoconfigure.SpringBootApplication; 
import org.springframework.context.annotation.Bean; 
import org.springframework.messaging.converter.MappingJackson2MessageConverter; 
import org.springframework.stereotype.Service; 

@SpringBootApplication 
public class ProducerApplication implements CommandLineRunner { 

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

    @Bean 
    Queue queue() { 
     return new Queue("queue", false); 
    } 

    @Bean 
    TopicExchange exchange() { 
     return new TopicExchange("exchange"); 
    } 

    @Bean 
    Binding binding(Queue queue, TopicExchange exchange) { 
     return BindingBuilder.bind(queue).to(exchange).with("queue"); 
    } 

    @Bean 
    public MappingJackson2MessageConverter jackson2Converter() { 
     MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter(); 
     return converter; 
    } 

    @Autowired 
    private Sender sender; 

    @Override 
    public void run(String... args) throws Exception { 
     sender.sendToRabbitmq(new Foo(), new Bar()); 
    } 
} 

@Service 
class Sender { 

    @Autowired 
    private RabbitMessagingTemplate rabbitMessagingTemplate; 
    @Autowired 
    private MappingJackson2MessageConverter mappingJackson2MessageConverter; 

    public void sendToRabbitmq(final Foo foo, final Bar bar) { 

     this.rabbitMessagingTemplate.setMessageConverter(this.mappingJackson2MessageConverter); 

     this.rabbitMessagingTemplate.convertAndSend("exchange", "queue", foo); 
     this.rabbitMessagingTemplate.convertAndSend("exchange", "queue", bar); 

    } 
} 

class Bar { 
    public int age = 33; 
} 

class Foo { 
    public String name = "gustavo"; 
} 

उपभोक्ता MICROSERVICE

package demo.consumer; 

import org.springframework.amqp.rabbit.annotation.EnableRabbit; 
import org.springframework.amqp.rabbit.annotation.RabbitListener; 
import org.springframework.beans.factory.annotation.Autowired; 
import org.springframework.boot.CommandLineRunner; 
import org.springframework.boot.SpringApplication; 
import org.springframework.boot.autoconfigure.SpringBootApplication; 
import org.springframework.stereotype.Service; 

@SpringBootApplication 
@EnableRabbit 
public class ConsumerApplication implements CommandLineRunner { 

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

    @Autowired 
    private Receiver receiver; 

    @Override 
    public void run(String... args) throws Exception { 

    } 

} 

@Service 
class Receiver { 
    @RabbitListener(queues = "queue") 
    public void receiveMessage(Foo foo) { 
     System.out.println("Received <" + foo.name + ">"); 
    } 

    @RabbitListener(queues = "queue") 
    public void receiveMessage(Bar bar) { 
     System.out.println("Received <" + bar.age + ">"); 
    } 
} 

class Foo { 
    public String name; 
} 

class Bar { 
    public int age; 
} 

और यहां अपवाद है जो मुझे मिल रहा है:

org.springframework.amqp.rabbit.listener.exception.ListenerExecutionFailedException: Listener method could not be invoked with the incoming message 
Endpoint handler details: 
Method [public void demo.consumer.Receiver.receiveMessage(demo.consumer.Bar)] 
Bean [[email protected]] 
    at org.springframework.amqp.rabbit.listener.adapter.MessagingMessageListenerAdapter.invokeHandler(MessagingMessageListenerAdapter.java:116) 
    at org.springframework.amqp.rabbit.listener.adapter.MessagingMessageListenerAdapter.onMessage(MessagingMessageListenerAdapter.java:93) 
    at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.doInvokeListener(AbstractMessageListenerContainer.java:756) 
    at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.invokeListener(AbstractMessageListenerContainer.java:679) 
    at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.access$001(SimpleMessageListenerContainer.java:83) 
    at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$1.invokeListener(SimpleMessageListenerContainer.java:170) 
    at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.invokeListener(SimpleMessageListenerContainer.java:1257) 
    at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.executeListener(AbstractMessageListenerContainer.java:660) 
    at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.doReceiveAndExecute(SimpleMessageListenerContainer.java:1021) 
    at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.receiveAndExecute(SimpleMessageListenerContainer.java:1005) 
    at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.access$700(SimpleMessageListenerContainer.java:83) 
    at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$AsyncMessageProcessingConsumer.run(SimpleMessageListenerContainer.java:1119) 
    at java.lang.Thread.run(Thread.java:745) 
Caused by: org.springframework.amqp.support.converter.MessageConversionException: Cannot handle message 
    ... 13 common frames omitted 
Caused by: org.springframework.messaging.converter.MessageConversionException: No converter found to convert to class demo.consumer.Bar, message=GenericMessage [payload=byte[10], headers={amqp_receivedRoutingKey=queue, amqp_receivedExchange=exchange, amqp_deliveryTag=1, amqp_deliveryMode=PERSISTENT, amqp_consumerQueue=queue, amqp_redelivered=false, id=87cf7e06-a78a-ddc1-71f5-c55066b46b11, amqp_consumerTag=amq.ctag-msWSwB4bYGWVO2diWSAHlw, contentType=application/json;charset=UTF-8, timestamp=1433989934574}] 
    at org.springframework.messaging.handler.annotation.support.PayloadArgumentResolver.resolveArgument(PayloadArgumentResolver.java:115) 
    at org.springframework.messaging.handler.invocation.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:77) 
    at org.springframework.messaging.handler.invocation.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:127) 
    at org.springframework.messaging.handler.invocation.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:100) 
    at org.springframework.amqp.rabbit.listener.adapter.MessagingMessageListenerAdapter.invokeHandler(MessagingMessageListenerAdapter.java:113) 
    ... 12 common frames omitted 

अपवाद कहते हैं कोई कनवर्टर है, और है कि मेरी समस्या मुझे पता नहीं है कैसे (उपभोक्ता पक्ष में MappingJackson2MessageConverter कनवर्टर स्थापित करने के लिए कृपया ध्यान दें कि मैं org.springframework उपयोग करना चाहते हैं वह यह है कि सच है, .messaging.converter.MappingJackson2MessageConverter और नहीं org.springframework.amqp.support.converter.JsonMessageConverter)

किसी भी विचार?

बस मामले में, आप इस नमूना परियोजना कांटा कर सकते हैं: https://github.com/gustavoorsi/rabbitmq-consumer-receiver

+0

यहाँ एक नज़र डालें: कि उदाहरण का उपयोग करता है में http://stackoverflow.com/questions/29337550/using-rabbitlistener-with-jackson2jsonmessageconverter – stalet

+0

** org.springframework.amqp.support.converter.Jackson2JsonMessageConverter ** (जो निर्भरता वसंत-एमक्यूपी से संबंधित है), मेरे मामले में मैं ** org.springframework.messaging.converter.MappingJackson2MessageConverter ** (जो वसंत-संदेश से संबंधित है) का उपयोग करना चाहता हूं। – Gustavo

उत्तर

12

ठीक है, मुझे अंततः यह काम मिल गया।

स्प्रिंग एक PayloadArgumentResolver का उपयोग करता है, निकालने बदलने और विधि पैरामीटर @RabbitListener साथ एनोटेट करने के लिए परिवर्तित संदेश स्थापित करने के लिए। किसी भी तरह हमें इस ऑब्जेक्ट में मैपिंग जैक्सन 2 मेसेज कनवर्टर सेट करने की आवश्यकता है।

तो, उपभोक्ता ऐप में, हमें खरगोश लिस्टरनर कॉन्फ़िगरर लागू करने की आवश्यकता है।configureRabbitListeners (RabbitListenerEndpointRegistrar रजिस्ट्रार) अधिभावी करके हम इस कारखाने हम संदेश कनवर्टर स्थापित करने के लिए, एक कस्टम DefaultMessageHandlerMethodFactory सेट कर सकते हैं, और कारखाने सही परिवर्तित के साथ हमारे PayloadArgumentResolver पैदा करेगा।

यहां कोड का एक स्निपेट है, मैंने git project भी अपडेट किया है।

ConsumerApplication.java

package demo.consumer; 

import org.springframework.amqp.rabbit.annotation.EnableRabbit; 
import org.springframework.amqp.rabbit.annotation.RabbitListener; 
import org.springframework.amqp.rabbit.annotation.RabbitListenerConfigurer; 
import org.springframework.amqp.rabbit.listener.RabbitListenerEndpointRegistrar; 
import org.springframework.beans.factory.annotation.Autowired; 
import org.springframework.boot.SpringApplication; 
import org.springframework.boot.autoconfigure.SpringBootApplication; 
import org.springframework.context.annotation.Bean; 
import org.springframework.messaging.converter.MappingJackson2MessageConverter; 
import org.springframework.messaging.handler.annotation.support.DefaultMessageHandlerMethodFactory; 
import org.springframework.stereotype.Service; 

@SpringBootApplication 
@EnableRabbit 
public class ConsumerApplication implements RabbitListenerConfigurer { 

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

    @Bean 
    public MappingJackson2MessageConverter jackson2Converter() { 
     MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter(); 
     return converter; 
    } 

    @Bean 
    public DefaultMessageHandlerMethodFactory myHandlerMethodFactory() { 
     DefaultMessageHandlerMethodFactory factory = new DefaultMessageHandlerMethodFactory(); 
     factory.setMessageConverter(jackson2Converter()); 
     return factory; 
    } 

    @Override 
    public void configureRabbitListeners(RabbitListenerEndpointRegistrar registrar) { 
     registrar.setMessageHandlerMethodFactory(myHandlerMethodFactory()); 
    } 

    @Autowired 
    private Receiver receiver; 

} 

@Service 
class Receiver { 
    @RabbitListener(queues = "queue") 
    public void receiveMessage(Foo foo) { 
     System.out.println("Received <" + foo.name + ">"); 
    } 

    @RabbitListener(queues = "queue") 
    public void receiveMessage(Bar bar) { 
     System.out.println("Received <" + bar.age + ">"); 
    } 
} 

class Foo { 
    public String name; 
} 

class Bar { 
    public int age; 
} 

इसलिए, यह 2 संदेश कतार में जोड़ना होगा यदि आप निर्माता microservice चलाते हैं। एक जो फू ऑब्जेक्ट का प्रतिनिधित्व करता है और दूसरा जो एक बार ऑब्जेक्ट का प्रतिनिधित्व करता है। उपभोक्ता माइक्रोस्कोस चलाकर आप देखेंगे कि दोनों रिसीवर कक्षा में संबंधित विधि से उपभोग किए जाते हैं।


अपडेट किया गया मुद्दा:

वहाँ मेरी तरफ से मुझे लगता है कि कतार के बारे में एक वैचारिक समस्या है। मैं जो हासिल करना चाहता था वह @RabbitListener के साथ एनोटेटेड 2 विधियों की घोषणा करके संभव नहीं हो सकता है जो एक ही पंक्ति में इंगित करता है। उपरोक्त समाधान ठीक से काम नहीं कर रहा था। यदि आप rabbitmq को भेजते हैं, तो कहें, 6 फू संदेश और 3 बार संदेश, उन्हें Foo पैरामीटर के साथ श्रोता द्वारा 6 बार प्राप्त नहीं किया जाएगा। ऐसा लगता है कि श्रोता समानांतर में आते हैं इसलिए विधि श्रोता प्रकार के आधार पर कौन सा श्रोता आक्रमण करने का कोई तरीका नहीं है। मेरा समाधान (और मुझे यकीन नहीं है कि यह सबसे अच्छा तरीका है, मैं यहां सुझावों के लिए खुला हूं) प्रत्येक इकाई के लिए एक कतार बनाने के लिए है। तो अब, मैं queue.bar और queue.foo एक बार फिर, और अद्यतन @RabbitListener (कतारों = "queue.foo") , मैं कोड को नवीनीकृत किया है और आप में यह भी देख सकते हैं मेरा git repository

+1

1.5.0 (वर्तमान में मील का पत्थर 1) में सहायता करता है [वर्ग-स्तर '@ खरगोश लिस्टर '] (https://spring.io/blog/2015/05/08/spring-amqp-1-4-5-release-and -1-5-0-एम 1-उपलब्ध) इस उपयोग के मामले का समर्थन करने के लिए व्यक्तिगत तरीकों पर '@ खरगोश हैंडलर 'के साथ। –

+0

जो जानना अच्छा है। धन्यवाद ! – Gustavo

0

यह नहीं किया है अपने आप को लेकिन ऐसा लगता है जैसे आप एक RabbitTemplate की स्थापना करके उचित रूपांतरण रजिस्टर करने के लिए की जरूरत है। this Spring documentation में सेक्शन 3.6.2 पर एक नज़र डालें। मुझे पता है कि यह एएमक्यूपी कक्षाओं का उपयोग करके कॉन्फ़िगर किया गया है, लेकिन यदि आप जिस मैसेजिंग क्लास का उल्लेख कर रहे हैं वह संगत है, तो इसका कोई कारण नहीं है कि आप इसे प्रतिस्थापित नहीं कर सकते हैं। ऐसा लगता है कि this reference बताता है कि आप एक्सएमएल की बजाय जावा कॉन्फ़िगरेशन का उपयोग करके इसे कैसे कर सकते हैं। मैंने वास्तव में खरगोश का उपयोग नहीं किया है, इसलिए मेरे पास कोई व्यक्तिगत अनुभव नहीं है लेकिन मुझे यह जानना अच्छा लगेगा कि आप क्या खोजते हैं।

संबंधित मुद्दे