• JmsTemplate 发送方式


    ---恢复内容开始---

    背景:

    原来我准备是setDefaultDestinationName 设置队列的名称 发现 系统运行后  创建 的并不是队列 ,而是Topic  , 

    自己看下源码,发现在创建时候,需要观察session的类型

    JmsTemplate提供了3组*3,共计9个发送用的方法。
     
    发送的方法有3组:
    1. 基本的发送
    2. 转换并发送
    3. 转换、后处理再发送

    必需的资源


    必需的资源有:
    • javax.jms.ConnectionFactory
      ConnectionFactory是客户端编程的开始,由它依次获取Connection、Session、Message、MessageProducer或MessageConsumer,从而做好了发送或接收的准备。
    • javax.jms.Destination
      Destination是发送的目的地,或者接收的源
    实际上,我们提供了上述的资源之后,我们就是做了这样的指令:让JmsTemplate连接到Destination,从我们提供的ConnectionFactory中获取连接资源。
    P.S.如果你不了客户端编程模型,建议参考02. JMS客户端编程模型

    1.ConnectionFactory资源

    我们如何提供ConnectionFactory给JmsTemplate?凭借JmsTemplete提供的构造器或setter方法:
    • public JmsTemplate(ConnectionFactory connectionFactory)
    • public void setConnectionFactory(ConnectionFactory connectionFactory)
      # 继承自org.springframework.jms.support.JmsAccessor

    2.Destination资源

    我们如何提供Destination给JmsTemplate?
    我们有两个机会做这件事,第一次是在初始化的时候提供一个默认的Destination,第二次是在发送的时候提供一个明确的Destination。相关的方法:
    • public void setDefaultDestination(Destination destination)
      设置默认的Destination
    • public void send(Destination destination, MessageCreator messageCreator)
      将消息发送到指定的Destination
      MessageCreator接口用来提供创建消息的回调方法,后面再讲。
     
    JmsTemplate还提供了另一种获取Destination的方式:基于Destination解析器、Destination类型、Destination名字的获取。你可以使用下面的代码来指定解析器、Destination类型:
    1 // jt is instance of JmsTemplate
    2 jt.setDestinationResolver(new DynamicDestinationResolver()); // set Destination解析器
    3 jt.setPubSubDomain(false); // set Destinantion类型
    Destination解析器要实现org.springframework.jms.support.destination.DestinationResolver接口。解析器有默认的值,就是DynamicDestinationResolver,除非你要使用其他的解析器,否则不必调用setDestinationResolver。所以,第2行代码是多余的。
    Destination类型有2个:false-Queue类型,true-Topic类型;默认为false。所以,第3行代码是多余的。
    设置了解析器、类型,或者直接使用默认的值,之后,就可以设置destination的name。JmsTemplate提供了两个方法:
    • public void setDefaultDestinationName(String destinationName)
      设置defaultDestination。这个方法和setDefaultDestination(Destination destination)做同样的事情,只是这个方法依赖于解析器和类型。
    • public void send(String destinationName, MessageCreator messageCreator)
      将消息发送到指定的Destination。这个方法和send(Destination destination, MessageCreator messageCreator)做同样的事情,只是这个方法依赖于解析器和类型。
     
    P.S.如何根据destinationName创建Destination实例?
    javax.jms.Session提供了两个方法,分别创建两种类型的Destination:
    • Queue createQueue(java.lang.String queueName)
      根据name创建Queue类型的Destination
    • Topic createTopic(java.lang.String topicName)
      根据name创建Topic类型的Destination
    public class DynamicDestinationResolver implements DestinationResolver {
        @Override
        public Destination resolveDestinationName(Session session, String destinationName, boolean pubSubDomain)
                throws JMSException {
            Assert.notNull(session, "Session must not be null");
            Assert.notNull(destinationName, "Destination name must not be null");
            if (pubSubDomain) {
                return resolveTopic(session, destinationName);
            }
            else {
                return resolveQueue(session, destinationName);
            }
        }
        protected Topic resolveTopic(Session session, String topicName) throws JMSException {
            return session.createTopic(topicName);
        }
        protected Queue resolveQueue(Session session, String queueName) throws JMSException {
            return session.createQueue(queueName);
        }
    }

    根据这份源码,可以帮助理解pubSubDomain的机制,以及将JMS的api和Spring的Destination解析器这两个知识点连接起来。

    1.基本的发送方法


    在前文我们已经接触了两个,它们都是在发送的同时指定Destination。现把它们和第3种一起介绍:
    • public void send(Destination destination, MessageCreator messageCreator)
      将消息发送到指定的Destination
    • public void send(String destinationName, MessageCreator messageCreator)
      将消息发送到指定的Destination。这个方法和send(Destination destination, MessageCreator messageCreator)做同样的事情,只是这个方法依赖于解析器和类型。
    • public void send(MessageCreator messageCreator)
      将消息发送到defaultDestination。
      这个方法要求提前设置defaultDestination,你可以调用setDefaultDestination(Destination destination)或者setDefaultDestinationName(String destinationName)来满足这个前提。
    在3个基本的发送方法中,都使用MessageCreator来创建消息。

    使用MessageCreator创建消息

    jms中的Message,是以接口javax.jms.Message为首的接口家族,这个家族的图谱是这样的:
    javax.jms.Message
        |---- BytesMessage
        |---- MapMessage
        |---- ObjectMessage
        |---- StreamMessage
        |---- TextMessage
    JMS将Message细分为5种类型,并在javax.jms.Session接口中分别定义了创建上述Message的多个方法,通常以create*Message为名,返回对应的Message类型。
     
    在JMS的api中,只有javax.jms.Session能创建消息。
     
    所以在Spring中,如果我们要创建Message,就要有Session。但是我们只有现成的ConnectionFactory,我们不应该走一遍从ConnectionFactory到Session的路,否则我们也不需要JmsTemplate帮我们发送了,因为剩下的工作也没多少了——关键是我们并没有从JMS的API中解脱出来。
    所以有了MessageCreator的接口,它定义了一个回调的方法:
    • Message createMessage(Session session)
    只要我们把MessageCreator的实例传给JmsTemplate,它就会在合适的时候调用这个方法,并发送返回的消息。
    下面给一个例子:
    复制代码
    1 jt.send(DESTINATION_NAME, new MessageCreator() {
    2     
    3     public Message createMessage(Session session) throws JMSException {
    4         String text = "A test for MessageCreator.";
    5         Message message = session.createTextMessage(text);
    6         return message;
    7     }
    8 });
    复制代码

    2.转换并发送的方法


    我们需要将数据装进JMS的Message,然后再发送。JMS的Message有5种具体的类型,不同的类型适合装载不同的数据。如果你不想做这段工作,而是希望能直接把数据丢给谁,然后由它来封装成Message——你只想准备数据,然后发送。那么接下来要介绍的方法,正适合你。
     
    Spring为转换定义了一个接口:org.springframework.jms.support.converter.MessageConverter,这个接口定义了下面的两个方法:
    • Message toMessage(Object object, Session session)
      发送时用到
    • Object fromMessage(Message message)
      接收时用到
    一般情况下,我们既不需要为MessageConverter提供实现,也不需要面向MessageConverter进行编程,所以我们实在没有必要关注上面的两个方法,扫一眼,有个大概的印象就够了。
     
    说回JmsTemplate,它定义了下面的方法来设置Converter:
    • public void setMessageConverter(MessageConverter messageConverter)
    而且在初始化的时候,会自动赋值一个SimpleMessageConverter类型的实例,所以我们甚至也不需要关心setMessageConverter方法了。
     
    说了这不多,总结一下,如果要用到转换,我们需要多做什么工作?答案是不需要!
    下面是具有转换功能的发送的方法,与基本的发送的方法进行对比:
    转换发送 基本发送
    • public void convertAndSend(Destination destination, Object message)
      将message转换成JMS的Message,并发送到指定的Destination
    • public void convertAndSend(String destinationName, Object message)
      将message转换成JMS的Message,并发送到指定的Destination。
    • public void convertAndSend(Object message)
      将message转换成JMS的Message,并发送到defaultDestination。
    • public void send(Destination destination, MessageCreator messageCreator)
      将消息发送到指定的Destination
    • public void send(String destinationName, MessageCreator messageCreator)
      将消息发送到指定的Destination。
    • public void send(MessageCreator messageCreator)
      将消息发送到defaultDestination。
    这两个系列的方法相似度很高,只是在创建消息的问题上有不同的处理:转换发送隐藏了消息的创建,基本发送需要实现MessageCreator接口来创建消息。
     
    接下来是一个demo,我们将上面的demo也拿下来,做一个对比:
    转换发送
    1 String message = "a message for test convertAndSend.";
    2 jt.convertAndSend(DESTINATION_NAME, message);
    基本发送
    复制代码
    1 jt.send(DESTINATION_NAME, new MessageCreator() {
    2     
    3     public Message createMessage(Session session) throws JMSException {
    4         String text = "A test for MessageCreator.";
    5         Message message = session.createTextMessage(text);
    6         return message;
    7     }
    8 }); 
    复制代码
    2比8,这纯粹是数学问题了。

    3.转换、后处理再发送的方法


    javax.jms.Message定义了很多的方法用来为消息添加头部信息或属性。但是如果我们要用转换并发送的方法,我们就接触不到Message类型的消息了,自然也无法为其添加任何信息。JmsTemplate提供了另一套发送的方法,允许我们使用自动转换,还允许我们能接触到转换后的消息,以便我们能做些什么。之后我们会返回处理后的Message,交给JmsTemplate发送。
     
    Spring定义了org.springframework.jms.core.MessagePostProcessor接口来做后处理的事,它定义了一个唯一的方法:
    • Message postProcessMessage(Message message)
      对消息进行处理,并返回处理后的消息
     
    让我们来看看这些方法,并与前文介绍的方法对比:
    转换、后处理、发送 转换、发送
    • public void convertAndSend(Destination destination, Object message, MessagePostProcessor postProcessor)
    • public void convertAndSend(String destinationName, Object message, MessagePostProcessor postProcessor)
    • public void convertAndSend(Object message, MessagePostProcessor postProcessor)
    • public void convertAndSend(Destination destination, Object message)
      将message转换成JMS的Message,并发送到指定的Destination
    • public void convertAndSend(String destinationName, Object message)
      将message转换成JMS的Message,并发送到指定的Destination。
    • public void convertAndSend(Object message)
      将message转换成JMS的Message,并发送到defaultDestination。
    再来看看两个demo的对比:
    转换、后处理、发送
    复制代码
    1 String message = "a message for test convertProcessAndSend.";
    2 jt.convertAndSend(DESTINATION_NAME, message,
    3         new MessagePostProcessor() {
    4             public Message postProcessMessage(Message message)
    5                     throws JMSException {
    6                 message.setIntProperty("order", 1);
    7                 return message;
    8             }
    9         }); 
    复制代码
    转换、发送
    1 String message = "a message for test convertAndSend.";
    2 jt.convertAndSend(DESTINATION_NAME, message); 
    在转换、后处理、发送中,我们为Message设置了一个属性:order=1.

    ---恢复内容结束---

  • 相关阅读:
    Spring boot返回值封装与业务异常
    Spring boot日志
    Rocket项目启动
    抉择
    C# 字符转ASCII码,ASCII码转字符 [转一下]
    xcode 学习笔记2:动态添加view
    unrecognized selector sent to instance 0x1b97e0' 问题解决记录
    xcode 学习笔记1:Interface Builder的使用
    xcode 学习笔记4:给WindowBase程序添加view
    xcode 学习笔记3:xcode目录结构
  • 原文地址:https://www.cnblogs.com/java-synchronized/p/7760007.html
Copyright © 2020-2023  润新知