ActiveMQ基本应用

点对点(queue)应用

特点:

1. 一条消息消费者只能有一个

2. 发送者发送消息和消费者消费消息没有时间上的关联性,无论消费者在生产者发送消息的时候是否处于运行状态,它都可以提取消息。

发布订阅(Topic)应用

特点:

1. 每个消息可以有多个消费者。

2. 生产者和消费者之间有时间上的相关性。订阅一个主题的消费者只能消费 自它订阅之后发布的消息

3. 消费者有持久化功能,持久化消费者,在处于不活跃状态期间,topic依旧会将消息发送给它,当此消费者活跃(上线)之后,讲获得不活跃期间,topic发送的消息

应用实现

消费端代码实现(queue为例):
     
// 创建连接工厂
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://127.0.0.1:61616");

// 通过连接工厂创建一个连接
Connection connection = connectionFactory.createConnection();
connection.start();

// 创建一个session
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);

// 通过session创建一个名字为TEST.FOO的queue目的地
Destination destination = session.createQueue("TEST.FOO");

// 为TEST.FOO这个queue目的地指定一个消费者
MessageConsumer consumer = session.createConsumer(destination);

// 消费者等待从TEST.FOO中获取消息,默认等待时间是1秒
Message message = consumer.receive(1000);
 
// 消息处理
if (message instanceof TextMessage) {
     TextMessage textMessage = (TextMessage) message;
     String text = textMessage.getText();
     System.out.println("Received: " + text);
} else {
     System.out.println("Received: " + message);
}
// 关闭消费者,session和连接
consumer.close();
session.close();
connection.close();

发送端代码实现(queue为例)


// 创建连接工厂
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://127.0.0.1:51616");

// 创建一个连接
Connection connection = connectionFactory.createConnection();
connection.start();


// 创建一个会话
Session session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE);


// 创建目的地 (Topic or Queue)
Destination destination = session.createQueue("TEST.FOO");


// 由session创建消息发送者,设置消息为非持久化消息
MessageProducer producer = session.createProducer(destination);
producer.setDeliveryMode(DeliveryMode.PERSISTENT);


// 创建文本消息
String text = "wo cao " + Thread.currentThread().getName();
TextMessage message = session.createTextMessage(text);


// 发送消息
System.out.println("Sent message: " + message.hashCode() + " : " + Thread.currentThread().getName());
producer.send(message);
String text1 = "wo cao1111 " + Thread.currentThread().getName();
TextMessage message1 = session.createTextMessage(text1);
producer.send(message1);


// 关闭session和连接
session.commit();
session.close();
connection.close();


注意:手写代码的方式,非在一些特定场景下,例如,批量消息处理需要一个事务管理,否则不建议在项目中手写mq的发送端和消费端的实现,仅作为平时学习所用,请使用者务必注意在后续的应用文档中不再做特殊说明。接下来将介绍spring支持的方式,引导使用者在项目中使用mq

提示:使用者在使用spring配置的时候,切勿简单拷贝复制,有些配置是需要根据所在项目业务使用场景按需设置的,而这些配置给出的值可能只是一个示例值

ActiveMq的链接工厂配置


<!-- ActiveMQ 连接工厂 -->

 <bean id="advancedConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">

    <property name="brokerURL" value="failover:(tcp://localhost:61616,tcp://localhost:71717)?randomize=false"></property><!--需要连接的mq的tcp地址 -->

    <property name="producerWindowSize" value="1024000"></property><!--如果要让异步流控生效,必须设置生产者收到应答前能发送的最大字节数-->

    <property name="useAsyncSend" value="false" /><!-- activemq默认的情况下就是异步发送,但没有使用事务的持久化消息会强制使用同步发送。如果将useAsyncSend设置为true,会强制使用异步发送,可能导致消息丢失,但性能可以提高好几倍 --> 

    <property name="alwaysSyncSend" value="false"></property><!-- 不论任何情况下,都使用同步,能第一时间得到消息被堵塞的通知 -->

 <!--<property name="clientID" value="" ></property>持久化订阅必须配置clientId,相同ClientId的客户端不能同时连接到MQ服务器,因此可以用来做热备 -->  

</bean>
    
<!-- SpringCaching 连接工厂 为客户端提Session供缓存功能 -->

<bean id="advancedCachingConnectionFactory" class="org.springframework.jms.connection.CachingConnectionFactory">
       
   <property name="targetConnectionFactory" ref="advancedConnectionFactory" /> <!-- mq 连接工厂 -->
    
   <property name="sessionCacheSize" value="10" /><!-- 设置session缓存个数(示例值),如果连接工厂是生产者使用,那么那么sessionSize的数量影响到并发的性能,如果是消费者使用,那么这个设置没有影响-->
 
</bean>
 
 
  

工厂说明如下:

1. 针对CachingConnectionFactory中的sessionCacheSize设置要做如下说明:

seesion是仅次于连接的昂贵资源,频繁的开启关闭session会影响到性能,CachingConnectionFactory能够将session缓存起来,供于下一次使用,至于缓存个数的设置,消费端的设置,建议与consumer的最大个数保持一致,注意,CachingConnectionFactory工厂只能创建一个连接,并且保持连接,供多个spring监听使用


2. ActiveMQConnectionFactory也能够直接使用,只是为每一个监听创建了一个tcp连接

3.使用failover机制做连接,可以保证客户端不会因为其中一个节点挂死而影响服务,在服务器主从配置情况下,第一个ip应该设置为主机ip,后面跟随从机ip。randomize=false,保证在轮询尝试连接所提供的ip时不是随机选取而是按顺序选择的


ActiveMq消息目的地配置

<!-- 定义消息的目的地址(queue)-->

<bean id="myQueue" class="org.apache.activemq.command.ActiveMQQueue">
    <constructor-arg value="TestQueue" /><!-- queue名字 -->
</bean>
 
<!-- 定义消息的目的地址(topic) -->
<bean id="myTopic" class="org.apache.activemq.command.ActiveMQTopic">
    <constructor-arg value="testTopic"/><!-- topic名字 -->
</bean>
 
<!-- 下面是虚拟topic的使用 -->
 
<!-- 发送端配置发送的topic-->
<bean id="senderTopic" class="org.apache.activemq.command.ActiveMQTopic">
    <constructor-arg value="VirtualTopic.testTopic"/><!-- topic名字,注意这里必须要带上VirtualTopic. -->
</bean>
 
<!-- 消费端配置监听的queue -->
<bean id="hehe" class="org.apache.activemq.command.ActiveMQQueue">
    <constructor-arg value="VirtualTopicConsumers.qmpc.VirtualTopic.testTopic"/><!-- queue名字,注意前缀VirtualTopicConsumers是根据服务器配置填写,不能随意填写,结尾必须带上VirtualTopic.testTopic -->
</bean>
 

注意:服务器配置参见高可用的ActiveMQ Server建设,建议在使用虚拟topic时,按照这样的规则命名,前缀.业务(部件).虚拟topic名 这样的格式命名消费端监听的queue


发送端jmsTemplate配置

 <!- 发送端JmsTemplate配置 -->
<bean id="sender" class="org.springframework.jms.core.JmsTemplate" >
    
 <property name="connectionFactory" ref="advancedCachingConnectionFactory" /><!-- 连接工厂 -->
       
 <property name="explicitQosEnabled" value="true" /> <!-- 使 deliveryMode, priority, timeToLive设置生效 -->
 
 <property name="deliveryPersistent" value="true" /><!-- 设置NON_PERSISTENT模式, 默认为PERSISTENT -->
       
 <property name="priority" value="4"/><!-- 设置优先级, 默认为4 越高优先级越高。kahaDB只支持3种优先级,<4,=4,>4 -->

 <property name="timeToLive" value="30000" /><!-- 过期时间,毫秒(示例值)默认是不过期 -->

</bean>
 
<!-- 发送端bean配置 -->

<bean id="sender" class="com.test.Sender">

    <property name="jmsTemplate" ref="sender"/> <!-- 发送模版 -->
		
    <property name="destination" ref="myQueue"/> <!-- 发送到的目的地queue或者是topic -->


</bean>
 

说明:虽然NON_PERSISTENT性能上要比PERSISTENT高不少,但是出于对消息可靠性的考虑,还是建议将PERSISTENT打开,PERSISTEN有一个最大的好处在于,持久化的消息在mq服务器宕机之后,消息不会丢失,在重启服务的时候,消息将恢复,而非持久话的消息,在有效时间内,mq服务down机之后,消息会丢失掉。过期时间的设置,必须设置过期时间,如果不设置过期时间有一个明显的缺陷,就是可能存在消息不会被消费掉,又由于不过期,这样的消息会占用磁盘空间,由于客户端设置了非持久化和持久化消息都会被放置到死信队列,这样,消息过期之后,会将消息放置在死信队列,如果不需要了,可以人为清除死信队列中的信息,释放空间

发送端代码示例

public class Sender
{
    private JmsTemplate jmsTemplate;
    private Destination destination;
    public void send(final Serializable message)
    {
        MessageCreator creator = new MessageCreator()
        {
            @Override
            public Message createMessage(Session session) throws JMSException
            {
                if (message instanceof String)
                {
                    Message msg = session.createTextMessage((String) message);

                    return msg;
                }
                else
                {
                    ObjectMessage objMessage = session.createObjectMessage();
                    objMessage.setObject(message);
                    return objMessage;
                }
            }
        };
        jmsTemplate.send(destination, creator);
    }
    public JmsTemplate getJmsTemplate()
    {
        return jmsTemplate;
    }
    public void setJmsTemplate(JmsTemplate jmsTemplate)
    {
        this.jmsTemplate = jmsTemplate;
    }
    public Destination getDestination()
    {
        return destination;
    }
    public void setDestination(Destination destination)
    {
        this.destination = destination;
    }
}


消费端Listener配置



<bean id="taskContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">

  <property name="connectionFactory" ref="advancedCachingConnectionFactory" /> <!-- 连接工厂-->

  <property name="destination" ref="orderTaskQueueA" /><!-- 目的地址queue或者topic -->

  <property name="messageListener" ref="consumer" /><!-- 消息消费监听对象,实现MessageListener 接口 -->

  <property name="concurrentConsumers" value="2" />  <!-- 初始2个Consumer, 可动态扩展到10(示例值) -->

  <property name="maxConcurrentConsumers" value="10" /> <!-- 最大允许的消费者数量(示例值) -->
  <property name="sessionAcknowledgeModeName" value="CLIENT_ACKNOWLEDGE" /><!-- 在使用Spring的情况下,AUTO确认模式会在消息进入业务方法前进行回应,Client则会在之后,DUL_OK可以延迟消息回应并批量处理,但这可能导致消息重复发送。 -->

  <property name="sessionTransacted" value="true"></property> <!--事务开关 -->

  <property name="subscriptionDurable" value="true"></property><!-- 是否持久化订阅,topic有效,次属性仅在订阅topic时有效,在使用queue消费时,请注释掉,否则会影响启动 -->

  <property name="durableSubscriptionName" value="topicYkListenerA" ></property><!--持久化订阅名称,次属性仅在订阅topic时有效,在使用queue消费时,请注释掉,否则会影响启动 -->

</bean>

<!-- 消息处理对象 -->
<bean id="consumer" class="com.test.Consumer"></bean>

说明:

sessionAcknowledgeModeName设置为CLIENT_ACKNOWLEDGE,为的是保证消息在处理之后应答,这样也是保证消息不丢失的一个做法,如果设置为AUTO模式,在业务处理之前,就回答服务器我收到消息了,这时服务器是不会理会业务处理是否成功(因为可能会由于异常或者其他因素导致代码中断而处理不成功),将此消息认为是消费过了,而删除掉。

在使用消息订阅(Topic)时,建议使用订阅持久化,订阅持久化可以让消费端处在不活跃状态期间依旧能够收到消息


consumer对象代码示例:
public class Consumer implements MessageListener
{
    public void onMessage(Message msg)
    {
      //消息处理过程.....
       
    }
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值