前言
  一个JMS消息分为:
  1.消息头
  2.属性
  3.消息体(有效负载)
   1.消息头
   1.1 系统默认分配的消息头
     - a. JMSDestination :Topic 和Queue用此属性标识目的地,二者都是Destination类型。
            javax.jms.Message接口有对应的getJMSDestination()方法。
                持久化 : javax.jms.DeliveryMode.PERSISTENT
              非持久化 : javax.jms.DeliveryMode.NON_PERSISTENT
              javax.jms.MessageProducer接口,中有设置该消息头的方法。
              JmsTemplate设置方式如下:
  JmsTemplate.setDeliveryPersistent(boolean deliveryPersistent);
     - c.JMSMessageID:String类型,消息的唯一标示
- d.JMSTimeStamp:由MessageProducer在调用send时自动,设置。long类型。用于确定发送消息和该消息被消息者实际接收的时间间隔。
- e.JMSExpiration:设置消息的过期时间。
MessageProducer.setTimeToLive()//进行设置。  JmsTemplate.setTimeToLive(long timeToLive)
          默认不过期,javax.jms.Message.DEFAULT_TIME_TO_LIVE(该值为0,表示永不过期)
     - f.JMSRedelivered:标示该消息将重复给消费者。如果为true,表示该消息将被重新发送,仅在需要确认消息的模式下有效。
- g.JMSPriority:JMS优先级,0-4普通,5-9加急,加急会比普通优先发送。
          默认优先级为javax.jms.Message.DEFAULT_PRIORITY(即为4)。
   1.2 为开发者分配的消息头
     - a.JMSReplayTo:设置应答队列,仅仅对Queue模式有用。
            JmsTemplate没有主动设置的部分,sendAndReceive方法时会临时生成一个队列。
     - b.JMSCorrelationID:业务关联ID,一般情况下用于应答,存储上一条消息的JMSMessageID,表示 是这条消息的应答。
            MessageListenerAdapter.onMessage会进行设置。
     - c.JMSType:可选消息头,用于标注类型和有效负载类型,非MapMessage。某些消息系统需要这个字段。
2.消息属性
      类似附加消息头。可以是boolean,Byte,Short,Integer,Long,float,double,Object类型
   2.1应用特定的属性(自定义数据)
  一般用于消息选择器。Message接口有对应的get,set方法。
  jmsTemplate 的设置方式如下:
  jmsTemplate.convertAndSend(queue, obj, new MessagePostProcessor() {  @Override  public Message postProcessMessage(Message message) throws JMSException {  for (Entry<String, String> head : appendHeaders.entrySet()) {  message.setStringProperty(head.getKey(), head.getValue());  }  return message;  }  });
   2.2 JMS定义的属性
  默认以JMSX开头,这些消息头是可选的。
              | 名称 | 类型 | 由谁设置 | 作用 | 
         | JMSXUserID | String | MQ在发送时设置 | 发送消息的UserId | 
         | JMSXAppID | String | MQ在发送时设置 | 发送消息的应用ID | 
         | JMSXDeliveryCount | int | MQ在接收时设置 | 消息尝试发送的次数,第一次为1,第二次为2  | 
         | JMSXGroupID | String | client(调用者)端 | 消息所属的分组ID | 
         | JMSXGroupSeq | int | Client(调用者)端 | 消息在组中的序号,第一个消息为1,第二个消息为2  | 
         | JMSXProducerTXID | String | MQ在接收时设置 | 消息生成时的事务ID | 
         | JMSXConsumerTXID | String | MQ在接收时设置 | 消息被消费时的事务ID | 
         | JMSXRcvTimestamp | long | MQ在接收时设置 | JMS把消息发送的消费者的时间 | 
         | JMSXState | int | MQ |   假设存在一个消息仓库, 该消息仓库包含每个发送到消费者 的消息的独立副本。 这些副本的存在从最初的信息开始被送时就存在 每个副本的状态,是如下状态其中之一: 1(等待)2(就绪)3(过期)4(保留) 因为状态对生成者和消费者都无用, 所以不由他们提供。 这个状态仅仅用于在仓库中查询, JMS没有对应的API | 
     
   2.3MQ特定的消息
  用于支持厂商的私有特性。我在工作中没有使用到,不做介绍。
   3.消息类型
  JMS提供了6个消息接口,分别是:
     - Message
- BytesMessage,
- MapMessage,
- ObjectMessage(传递序列化后的消息),
- StreamMessage,
- TextMessage。
Message
  若使用Message,仅仅包含消息头和消息属性。基本仅仅用作事件通知。广播,警告,或者通知 中。
   TextMessage
  使用setText设置有效负载。getText获取消息。
   ObjectMessage
  setObject方法,注意这个对象必须要序列化。
   BytesMessage
  原始字节流作为有效负载
  设置消息类似java.io.DataInputStream和java.io.DataOutputStream方法。
  BytesMessage byteMessage=Session.createByteSession();  byteMessage.writeChar('c');  byteMessage.writeInt(10);  byteMessage.writeUTF("O my god");
   StreamMessage
  负载为java原数据类型流.允许将null写入流。读取的顺序与写入的顺序一致。
  读取时的类型转换规则如下:
              | 写类型 | 读可转换的类型 | 
         | boolean | boolean,String | 
         | byte | byte,short,int,long,String | 
         | short | short,int,long,String | 
         | char | char,String | 
         | long | long,String | 
         | int | int,long,String | 
         | float | float,double,String | 
         | String | String,boolean,byte,short,int,long,float,double | 
         | byte[] | byte[] | 
     
  若读取时遇到异常,尝试重新读取,需要调用reset方法,将读取指针返回到开始的地方。
   MapMessage
      负载为一组键值对.
      JMS客户端试图读取,一个不存在的值时,该值视为null。
      注意:    
      getObject方法会对不存在的映射放回null
      大多数的原始类似取值函数会返回,java.lang.NumberFormatException。
      getBoolean()方法将为null值返回false;
      getString(),可能返回null,或者一个空字符串。
      getChar(),会抛出java.lang.NullPointerException。
  为了避免上述问题,MapMessage提供了一个itemExists()的测试方法。另外getMapNames()可以让JMS客户端列举出Key。
   总结
      这篇blog,基本上都是JMS消息的概念,下篇blog会介绍activemq的负载均衡的搭建,预计下周完成。