Spring整合JMS(三)——MessageConverter介绍

简介:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
1.4      消息转换器MessageConverter
MessageConverter的作用主要有两方面,一方面它可以把我们的非标准化Message对象转换成我们的目标Message对象,这主要是用在发送消息的时候;另一方面它又可以把我们的Message对象转换成对应的目标对象,这主要是用在接收消息的时候。
下面我们就拿发送一个对象消息来举例,假设我们有这样一个需求:我们平台有一个发送邮件的功能,进行发送的时候我们只是把我们的相关信息封装成一个JMS消息,然后利用JMS进行发送,在对应的消息监听器进行接收到的消息处理时才真正的进行消息发送。
假设我们有这么一个Email对象:
          
Java代码  收藏代码
     public  class  Email  implements  Serializable {
                
         private  static  final  long  serialVersionUID = -658250125732806493L;
                
         private  String receiver;
         private  String title;
         private  String content;
                
         public  Email(String receiver, String title, String content) {
             this .receiver = receiver;
             this .title = title;
             this .content = content;
         }
                
         public  String getReceiver() {
             return  receiver;
         }
                
         public  void  setReceiver(String receiver) {
             this .receiver = receiver;
         }
                
         public  String getTitle() {
             return  title;
         }
                
         public  void  setTitle(String title) {
             this .title = title;
         }
                
         public  String getContent() {
             return  content;
         }
                
         public  void  setContent(String content) {
             this .content = content;
         }
                
         @Override
         public  String toString() {
             StringBuilder builder =  new  StringBuilder();
             builder.append( "Email [receiver=" ).append(receiver).append( ", title=" )
                     .append(title).append( ", content=" ).append(content).append( "]" );
             return  builder.toString();
         }
                   
     }
        这个Email对象包含了一个简单的接收者email地址、邮件主题和邮件内容。我们在发送的时候就把这个对象封装成一个ObjectMessage进行发送。代码如下所示:
Java代码  收藏代码
     public  class  ProducerServiceImpl  implements  ProducerService {
                
         @Autowired
         private  JmsTemplate jmsTemplate;    
               
         public  void  sendMessage(Destination destination,  final  Serializable obj) {
             jmsTemplate.send(destination,  new  MessageCreator() {
                
                 public  Message createMessage(Session session)  throws  JMSException {
                     ObjectMessage objMessage = session.createObjectMessage(obj);
                     return  objMessage;
                 }
                           
             });
         }
                
     }
        这是对应的在没有使用MessageConverter的时候我们需要 new 一个MessageCreator接口对象,然后在其抽象方法createMessage内部使用session创建一个对应的消息。在使用了MessageConverter的时候我们在使用JmsTemplate进行消息发送时只需要调用其对应的convertAndSend方法即可。如:
          
Java代码  收藏代码
     public  void  sendMessage(Destination destination,  final  Serializable obj) {
         //未使用MessageConverter的情况
         /*jmsTemplate.send(destination, new MessageCreator() {
              
             public Message createMessage(Session session) throws JMSException {
                 ObjectMessage objMessage = session.createObjectMessage(obj);
                 return objMessage;
             }
                      
         });*/
         //使用MessageConverter的情况
         jmsTemplate.convertAndSend(destination, obj);
     }
这样JmsTemplate就会在其内部调用预定的MessageConverter对我们的消息对象进行转换,然后再进行发送。
        这个时候我们就需要定义我们的MessageConverter了。要定义自己的MessageConverter很简单,只需要实现Spring为我们提供的MessageConverter接口即可。我们先来看一下MessageConverter接口的定义:
Java代码  收藏代码
     public interface MessageConverter {
                
         Message toMessage(Object object, Session session) throws JMSException, MessageConversionException;
                
         Object fromMessage(Message message) throws JMSException, MessageConversionException;
                
     }
        我们可以看到其中一共定义了两个方法fromMessage和toMessage,fromMessage是用来把一个JMS Message转换成对应的Java对象,而toMessage方法是用来把一个Java对象转换成对应的JMS Message。因为我们已经知道上面要发送的对象就是一个Email对象,所以在这里我们就简单地定义一个EmailMessageConverter用来把Email对象和对应的ObjectMessage进行转换,其代码如下:
          
Java代码  收藏代码
     import javax.jms.JMSException;
     import javax.jms.Message;
     import javax.jms.ObjectMessage;
     import javax.jms.Session;
                
     import org.springframework.jms.support.converter.MessageConversionException;
     import org.springframework.jms.support.converter.MessageConverter;
                
     public class EmailMessageConverter implements MessageConverter {
                
         public Message toMessage(Object object, Session session)
                 throws JMSException, MessageConversionException {
             return session.createObjectMessage((Serializable) object);
         }
                
         public Object fromMessage(Message message) throws JMSException,
                 MessageConversionException {
             ObjectMessage objMessage = (ObjectMessage) message;
             return objMessage.getObject();
         }
                
     }
          
        这样当我们利用JmsTemplate的convertAndSend方法发送一个Email对象的时候就会把对应的Email对象当做参数调用我们定义好的EmailMessageConverter的toMessage方法。
        定义好我们的EmailMessageConverter之后就需要指定我们用来发送Email对象的JmsTemplate对象的messageConverter为EmailMessageConverter,这里我们在Spring的配置文件中定义JmsTemplate bean的时候就指定:
          
Xml代码  收藏代码
     <!-- Spring提供的JMS工具类,它可以进行消息发送、接收等 -->
     <bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
         <!-- 这个connectionFactory对应的是我们定义的Spring提供的那个ConnectionFactory对象 -->
         <property name="connectionFactory" ref="connectionFactory"/>
         <!-- 消息转换器 -->
         <property name="messageConverter" ref="emailMessageConverter"/>
     </bean>
     <!-- 类型转换器 -->
     <bean id="emailMessageConverter" class="com.tiantian.springintejms.converter.EmailMessageConverter"/>
             
        到此我们的MessageConverter就定义好了,也能够进行使用了,接着我们来进行测试一下,定义测试代码如下所示:
          
Java代码  收藏代码
     @Test
     public void testObjectMessage() {
         Email email = new Email("zhangsan@xxx.com", "主题", "内容");
         producerService.sendMessage(destination, email);
     }
          
        上面destination对应的接收处理的MessageListener方法如下所示:
          
Java代码  收藏代码
     public class ConsumerMessageListener implements MessageListener {
                
         public void onMessage(Message message) {
                       
             if (message instanceof ObjectMessage) {
                 ObjectMessage objMessage = (ObjectMessage) message;
                 try {
                     Object obj = objMessage.getObject();
                     Email email = (Email) obj;
                     System.out.println("接收到一个ObjectMessage,包含Email对象。");
                     System.out.println(email);
                 } catch (JMSException e) {
                     e.printStackTrace();
                 }
             }
         }
                
     }
          
        之前说了MessageConverter有两方面的功能,除了把Java对象转换成对应的Jms Message之外还可以把Jms Message转换成对应的Java对象。我们看上面的消息监听器在接收消息的时候接收到的就是一个Jms Message,如果我们要利用MessageConverter来把它转换成对应的Java对象的话,只能是我们往里面注入一个对应的MessageConverter,然后在里面手动的调用,如:
          
Java代码  收藏代码
     public class ConsumerMessageListener implements MessageListener {
                
         private MessageConverter messageConverter;
                   
         public void onMessage(Message message) {
                       
             if (message instanceof ObjectMessage) {
                 ObjectMessage objMessage = (ObjectMessage) message;
                 try {
                     /*Object obj = objMessage.getObject();
                     Email email = (Email) obj;*/
                     Email email = (Email) messageConverter.fromMessage(objMessage);
                     System.out.println( "接收到一个ObjectMessage,包含Email对象。" );
                     System.out.println(email);
                 catch  (JMSException e) {
                     e.printStackTrace();
                 }
                           
             }
         }
                
         public  MessageConverter getMessageConverter() {
             return  messageConverter;
         }
                
         public  void  setMessageConverter(MessageConverter messageConverter) {
             this .messageConverter = messageConverter;
         }
                
     }
          
        当我们使用MessageListenerAdapter来作为消息监听器的时候,我们可以为它指定一个对应的MessageConverter,这样Spring在处理接收到的消息的时候就会自动地利用我们指定的MessageConverter对它进行转换,然后把转换后的Java对象作为参数调用指定的消息处理方法。这里我们再把前面讲解MessageListenerAdapter时定义的MessageListenerAdapter拿来做一个测试,我们指定它的MessageConverter为我们定义好的EmailMessageConverter。
          
Xml代码  收藏代码
     <!-- 消息监听适配器 -->
     <bean id= "messageListenerAdapter"  class = "org.springframework.jms.listener.adapter.MessageListenerAdapter" >
         <property name= "delegate" >
             <bean  class = "com.tiantian.springintejms.listener.ConsumerListener" />
         </property>
         <property name= "defaultListenerMethod"  value= "receiveMessage" />
         <property name= "messageConverter"  ref= "emailMessageConverter" />
     </bean>
     <!-- 消息监听适配器对应的监听容器 -->
     <bean id= "messageListenerAdapterContainer"  class = "org.springframework.jms.listener.DefaultMessageListenerContainer" >
         <property name= "connectionFactory"  ref= "connectionFactory" />
         <property name= "destination"  ref= "adapterQueue" />
         <property name= "messageListener"  ref= "messageListenerAdapter" /><!-- 使用MessageListenerAdapter来作为消息监听器 -->
     </bean>
          
        然后在我们的真正用于处理接收到的消息的ConsumerListener中添加一个receiveMessage方法,添加后其代码如下所示:
          
Java代码  收藏代码
     public  class  ConsumerListener {
                
         public  void  receiveMessage(String message) {
             System.out.println( "ConsumerListener通过receiveMessage接收到一个纯文本消息,消息内容是:"  + message);
         }
                   
         public  void  receiveMessage(Email email) {
             System.out.println( "接收到一个包含Email的ObjectMessage。" );
             System.out.println(email);
         }
                   
     }
          
        然后我们定义如下测试代码:
          
Java代码  收藏代码
     @Test
     public  void  testObjectMessage() {
         Email email =  new  Email( "zhangsan@xxx.com" "主题" "内容" );
         producerService.sendMessage(adapterQueue, email);
     }
          
        因为我们给MessageListenerAdapter指定了一个MessageConverter,而且是一个EmailMessageConverter,所以当MessageListenerAdapter接收到一个消息后,它会调用我们指定的MessageConverter的fromMessage方法把它转换成一个Java对象,根据定义这里会转换成一个Email对象,然后会把这个Email对象作为参数调用我们通过defaultListenerMethod属性指定的默认处理器方法,根据定义这里就是receiveMessage方法,但是我们可以看到在ConsumerListener中我们一共定义了两个receiveMessage方法,因为是通过转换后的Email对象作为参数进行方法调用的,所以这里调用的就应该是参数类型为Email的receiveMessage方法了。上述测试代码运行后会输出如下结果:
         说到这里可能有读者就会有疑问了,说我们在之前讲解MessageListenerAdapter的时候不是没有指定对应的MessageConverter,然后发送了一个TextMessage,结果Spring还是把它转换成一个String对象,调用了ConsumerListener参数类型为String的receiveMessage方法吗?那你这个MessageConverter在MessageListenerAdapter进行消息接收的时候也没什么用啊。
        其实还是有用的,在我们使用MessageListenerAdapter时,在对其进行初始化也就是调用其构造方法时,它会默认 new 一个Spring已经为我们实现了的MessageConverter——SimpleMessageConverter作为其默认的MessageConverter,这也就是为什么我们在使用MessageListenerAdapter的时候不需要指定MessageConverter但是消息还是会转换成对应的Java对象的原因。所以默认情况下我们使用MessageListenerAdapter时其对应的MessageListener的处理器方法参数类型必须是一个普通Java对象,而不能是对应的Jms Message对象。
        那如果我们在处理Jms Message的时候想使用MessageListenerAdapter,然后又希望处理最原始的Message,而不是经过MessageConverter进行转换后的Message该怎么办呢?这个时候我们只需要在定义MessageListenerAdapter的时候指定其MessageConverter为空就可以了。
          
Xml代码  收藏代码
     <!-- 消息监听适配器 -->
     <bean id= "messageListenerAdapter"  class = "org.springframework.jms.listener.adapter.MessageListenerAdapter" >
         <property name= "delegate" >
             <bean  class = "com.tiantian.springintejms.listener.ConsumerListener" />
         </property>
         <property name= "defaultListenerMethod"  value= "receiveMessage" />
         <property name= "messageConverter" >
             < null />
         </property>
     </bean>
          
        那么这个时候我们的真实MessageListener的处理器方法参数类型就应该是Jms Message或对应的Jms Message子类型了,不然就会调用不到对应的处理方法了。这里因为我们发送的是一个ObjectMessage,所以这里就添加一个对应的参数类型为ObjectMessage的receiveMessage方法了。
          
Java代码  收藏代码
     public  void  receiveMessage(ObjectMessage message)  throws  JMSException {
         System.out.println(message.getObject());
     }
          
        刚刚讲到Spring已经为我们实现了一个简单的MessageConverter,即org.springframework.jms.support.converter.SimpleMessageConverter,其实Spring在初始化JmsTemplate的时候也指定了其对应的MessageConverter为一个SimpleMessageConverter,所以如果我们平常没有什么特殊要求的时候可以直接使用JmsTemplate的convertAndSend系列方法进行消息发送,而不必繁琐的在调用send方法时自己 new 一个MessageCreator进行相应Message的创建。
这里我们也来看一下SimpleMessageConverter的定义,如果觉得它不能满足你的要求,那我们可以对它里面的部分方法进行重写,或者是完全实现自己的MessageConverter。
Java代码  收藏代码
     public  class  SimpleMessageConverter  implements  MessageConverter {
                
         public  Message toMessage(Object object, Session session)  throws  JMSException, MessageConversionException {
             if  (object  instanceof  Message) {
                 return  (Message) object;
             }
             else  if  (object  instanceof  String) {
                 return  createMessageForString((String) object, session);
             }
             else  if  (object  instanceof  byte []) {
                 return  createMessageForByteArray(( byte []) object, session);
             }
             else  if  (object  instanceof  Map) {
                 return  createMessageForMap((Map) object, session);
             }
             else  if  (object  instanceof  Serializable) {
                 return  createMessageForSerializable(((Serializable) object), session);
             }
               
             else  {
                 throw  new  MessageConversionException( "Cannot convert object of type ["  +
                         ObjectUtils.nullSafeClassName(object) +  "] to JMS message. Supported message "  +
                         "payloads are: String, byte array, Map<String,?>, Serializable object." );
             }
         }
                
         public  Object fromMessage(Message message)  throws  JMSException, MessageConversionException {
             if  (message  instanceof  TextMessage) {
                 return  extractStringFromMessage((TextMessage) message);
             }
             else  if  (message  instanceof  BytesMessage) {
                 return  extractByteArrayFromMessage((BytesMessage) message);
             }
             else  if  (message  instanceof  MapMessage) {
                 return  extractMapFromMessage((MapMessage) message);
             }
             else  if  (message  instanceof  ObjectMessage) {
                 return  extractSerializableFromMessage((ObjectMessage) message);
             }
             else  {
                 return  message;
             }
         }
                
         protected  TextMessage createMessageForString(String text, Session session)  throws  JMSException {
             return  session.createTextMessage(text);
         }
                
         protected  BytesMessage createMessageForByteArray( byte [] bytes, Session session)  throws  JMSException {
             BytesMessage message = session.createBytesMessage();
             message.writeBytes(bytes);
             return  message;
         }
                
         protected  MapMessage createMessageForMap(Map<?, ?> map, Session session)  throws  JMSException {
             MapMessage message = session.createMapMessage();
             for  (Map.Entry entry : map.entrySet()) {
                 if  (!(entry.getKey()  instanceof  String)) {
                     throw  new  MessageConversionException( "Cannot convert non-String key of type ["  +
                             ObjectUtils.nullSafeClassName(entry.getKey()) +  "] to JMS MapMessage entry" );
                 }
                 message.setObject((String) entry.getKey(), entry.getValue());
             }
             return  message;
         }
                
         protected  ObjectMessage createMessageForSerializable(Serializable object, Session session)  throws  JMSException {
             return  session.createObjectMessage(object);
         }
                
                
         protected  String extractStringFromMessage(TextMessage message)  throws  JMSException {
             return  message.getText();
         }
                
         protected  byte [] extractByteArrayFromMessage(BytesMessage message)  throws  JMSException {
             byte [] bytes =  new  byte [( int ) message.getBodyLength()];
             message.readBytes(bytes);
             return  bytes;
         }
                
         protected  Map extractMapFromMessage(MapMessage message)  throws  JMSException {
             Map<String, Object> map =  new  HashMap<String, Object>();
             Enumeration en = message.getMapNames();
             while  (en.hasMoreElements()) {
                 String key = (String) en.nextElement();
                 map.put(key, message.getObject(key));
             }
             return  map;
         }
                
         protected  Serializable extractSerializableFromMessage(ObjectMessage message)  throws  JMSException {
             return  message.getObject();
         }
                
     }





http://haohaoxuexi.iteye.com/blog/1900937











本文转自yunlielai51CTO博客,原文链接:http://blog.51cto.com/4925054/1283326,如需转载请自行联系原作者

相关文章
|
6月前
|
消息中间件 Java Spring
Spring Boot与JMS消息中间件的集成
Spring Boot与JMS消息中间件的集成
|
6月前
|
消息中间件 存储 Java
后端开发Spring框架之消息介绍 同步异步 JMS AMQP MQTT Kafka介绍
后端开发Spring框架之消息介绍 同步异步 JMS AMQP MQTT Kafka介绍
46 0
|
7月前
|
消息中间件 Java Spring
Spring Boot中异步消息JMS的讲解与通信实例
Spring Boot中异步消息JMS的讲解与通信实例
100 1
|
消息中间件 搜索推荐 Java
消息中间件JMS介绍、入门demo与spring整合
消息中间件JMS介绍、入门demo与spring整合
393 11
消息中间件JMS介绍、入门demo与spring整合
|
消息中间件 存储 网络协议
Spring Boot与消息(JMS、AMQP、RabbitMQ)
1.概述。 大多应用中,可通过消息服务中间件来提升系统异步通信、扩展解耦能力。 消息服务中两个重要概念: 消息代理(message broker)和目的地(destination)。 当消息发送者发送
305 0
|
Java 数据库连接 应用服务中间件
分布式事务之Spring/JPA/JMS事务(二)
分布式事务之Spring/JPA/JMS事务
306 0
分布式事务之Spring/JPA/JMS事务(二)
|
消息中间件 Java Spring
spring ehcache jms activemq 分布式实现方案
spring ehcache jms activemq 分布式实现方案
152 0
|
消息中间件 Java Spring
Spring消息之JMS.
一、概念 异步消息简介     与远程调用机制以及REST接口类似,异步消息也是用于应用程序之间通信的。     RMI、Hessian、Burlap、HTTP invoker和Web服务在应用程序之间的通信机制是同步的,即客户端应用程序直接与远程服务相交互,并且一直等到远程过程完成后才继续执行。
1247 0
|
消息中间件 存储 Java
JMS 消息传送模式、消息签收以及spring jmsTemplate配置
JMS 即 java message service 是为java提供了一种创建、发送、接收消息的通用方法。可以将复杂的系统进行业务分离,变成灵活的高度解耦合的布局。
2772 0
|
Java API Spring
Spring JMSTemplate 与 JMS 原生API比较
  博客分类:   JMS Spring 2.x       JMSUtil与Spring JmsTemplate的对比 Author:信仰 Date:2012-4-20 未完待续,截止日期2012-4-20 从以下几方面比较JMSUtil和Spring J...
1297 0