springboot 整合 activemq:传送自定义对象以及失败消息重试

标签: springboot  activemq 消息重试 ack 传递对象
15人阅读 评论(0) 收藏 举报
分类:
                <dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-activemq</artifactId>
			<version>2.0.0.BUILD-SNAPSHOT</version>
		</dependency>
import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.activemq.RedeliveryPolicy;
import org.apache.activemq.command.ActiveMQQueue;
import org.apache.activemq.command.ActiveMQTopic;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jms.config.DefaultJmsListenerContainerFactory;
import org.springframework.jms.core.JmsTemplate;

@Configuration
public class MessageConfig {
    @Bean
    public ActiveMQQueue queue(){
        return new ActiveMQQueue("m2m_queue");
    }
    @Bean
    public ActiveMQTopic topic(){
        return new ActiveMQTopic("topic_queue");
    }

    /**
     * 消息重试配置项
     * @return
     */
    @Bean
    public RedeliveryPolicy redeliveryPolicy(){
        RedeliveryPolicy redeliveryPolicy = new RedeliveryPolicy();
        redeliveryPolicy.setUseExponentialBackOff(true);//是否在每次失败重发是,增长等待时间
        redeliveryPolicy.setMaximumRedeliveryDelay(-1);//设置重发最大拖延时间,-1 表示没有拖延,只有setUseExponentialBackOff(true)时生效
        redeliveryPolicy.setMaximumRedeliveries(10);//重发次数
        redeliveryPolicy.setInitialRedeliveryDelay(1);//重发时间间隔
        redeliveryPolicy.setBackOffMultiplier(2);//第一次失败后重发前等待500毫秒,第二次500*2,依次递增
        redeliveryPolicy.setUseCollisionAvoidance(false);//是否避免消息碰撞
        return redeliveryPolicy;
    }

    @Bean
    public ActiveMQConnectionFactory factory(@Value("${spring.activemq.broker-url}")String url,RedeliveryPolicy redeliveryPolicy){
        ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("admin", "admin", url);
        factory.setRedeliveryPolicy(redeliveryPolicy);
        return factory;
    }

    @Bean
    public JmsTemplate jmsTemplate(ActiveMQConnectionFactory factory){
        JmsTemplate jmsTemplate = new JmsTemplate();
        jmsTemplate.setDeliveryMode(2);//设置持久化,1 非持久, 2 持久化
        jmsTemplate.setConnectionFactory(factory);
        /**
          SESSION_TRANSACTED = 0  事物提交并确认
          AUTO_ACKNOWLEDGE = 1    自动确认
                  CLIENT_ACKNOWLEDGE = 2    客户端手动确认   
                  DUPS_OK_ACKNOWLEDGE = 3    自动批量确认
                 INDIVIDUAL_ACKNOWLEDGE = 4    单条消息确认 activemq 独有                 */
        jmsTemplate.setSessionAcknowledgeMode(4);//消息确认模式 return jmsTemplate; } @Bean("jmsListener") public DefaultJmsListenerContainerFactory listener(ActiveMQConnectionFactory factory){ DefaultJmsListenerContainerFactory listener = new DefaultJmsListenerContainerFactory(); listener.setConnectionFactory(factory); listener.setConcurrency("1-10");//设置连接数 listener.setRecoveryInterval(1000L);//重连间隔时间 listener.setSessionAcknowledgeMode(4); return listener; } }
import javax.jms.JMSException;
import javax.jms.Queue;
import javax.jms.Topic;
import java.util.Date;
import java.util.List;


@Service
public class Proudcer {
    private final static Logger log= LoggerFactory.getLogger(Proudcer .class);
    @Autowired
    private JmsTemplate jmsTemplate;
    @Autowired
    private Queue queue;
    @Autowired
    private Topic topic;
 
    private void sendMessage() {
        String name="";
        try {
            name=queue.getQueueName();
            TbItem tbItem = new TbItem();
            tbItem.setId(1L);
            tbItem.setImage("image");
            jmsTemplate.send(name, session -> session.createObjectMessage(tbItem));
        } catch (JMSException e) {
            e.printStackTrace();
        }      
    }
  
}

先看jmsTemplate.send(name ,session ->session.createObjectMessage(tbItem));的源码(这里使用了lambda表达式)等价于

            jmsTemplate.send(name, new MessageCreator() {
                @Override
                //Session 对象是一个包含消息生产和消费的上下文应用(简而言之就是包含了生产者和消费者各种信息)
                public Message createMessage(Session session) throws JMSException {
                    return session.createObjectMessage(tbItem);//将自定义对象包裹进ActiveMQObjectMessage对象中
                }
            });
源码:  
        @Override
	public void send(final String destinationName, final MessageCreator messageCreator) throws JmsException {
		....//省略
	}

在activemq中有一个实体类ActiveMQObjectMessage的setObject 方法,就是将自定义的对象封装起来。

public class ActiveMQObjectMessage extends ActiveMQMessage implements ObjectMessage {

     ....

     public void setObject(Serializable newObject) throws JMSException {
        checkReadOnlyBody();
        this.object = newObject;
        setContent(null);
        ActiveMQConnection connection = getConnection();
        if (connection == null || !connection.isObjectMessageSerializationDefered()) {
            storeContent();
        }
    }
}

实体bean(必须实现Serializable)

public class TbItem implements Serializable{

    private Long id;

    private String image;

} 

消费者(监听者)

import com.cn.common.pojo.TbItem;
import org.apache.activemq.Message;
import org.apache.activemq.command.ActiveMQObjectMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.annotation.JmsListener;
import org.springframework.stereotype.Component;
import javax.jms.Session;

@Component
public class ItemESMessageListener {

	private final static Logger log= LoggerFactory.getLogger(ItemESMessageListener.class);
	
	@JmsListener(destination="m2m_queue",containerFactory = "jmsListener")
	public void onMessage(Message message,Session session) throws JMSException {
		try {
			log.info("=======接收到消息=={}",message);
			if (message instanceof ActiveMQObjectMessage){
				ActiveMQObjectMessage objectMessage=(ActiveMQObjectMessage)message;
				TbItem tbItem = (TbItem)objectMessage.getObject();
				String image = tbItem.getImage();
				Long id = tbItem.getId();
				log.info("===========image={}",image);
                              //如果执行了这个,那么即使后面的代码抛出了异常在catch块中执行session.recover()方法也不会重试,所以
                              //这个方法要放在最后执行
                                objectMessage.acknowledge();
                         }                         .....//其它代码       
                 } catch (Exception e) {        e.printStackTrace();
                        session.recover();
                 }}}

启动项目发现报错 This class is not trusted to be serialized as ObjectMessage payload


原因:在源码中为了避免收到恶意代码,引入了安全机制,只允许指定的包里的对象能够被传输。所以也就是说自定义的对象不在默认的指定包里。

解决办法:在上面配置 ActiveMQConnectionFactory时,加入factory.setTrustAllPackages(true)

    @Bean
    public ActiveMQConnectionFactory factory(@Value("${spring.activemq.broker-url}")String url,RedeliveryPolicy redeliveryPolicy){
        ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("admin", "admin", url);
        factory.setRedeliveryPolicy(redeliveryPolicy);
        factory.setTrustAllPackages(true);
        return factory;
    }





查看评论

spring boot集成ActiveMQ

spring boot集成ActiveMQ。
  • BuquTianya
  • BuquTianya
  • 2017-08-26 20:01:54
  • 5720

spring boot整合JMS(ActiveMQ实现)

一、安装ActiveMQ 具体的安装步骤,请参考我的另一篇博文: http://blog.csdn.net/liuchuanhong1/article/details/52057711 二、新建spr...
  • liuchuanhong1
  • liuchuanhong1
  • 2017-01-18 18:55:21
  • 31840

SpringBoot集成ActiveMQ

在实际项目中,很多时候需要消息中间件来进行分布式系统间的通信。它具有低耦合、可靠投递、广播、流量控制、最终一致性等一系列功能。 ActiveMQ 是Apache出品,最流行的,能力强劲的开源消息...
  • songhaifengshuaige
  • songhaifengshuaige
  • 2017-01-07 17:32:58
  • 8278

spring-boot 集成 activemq

ActiveMQ ActiveMQ 是Apache出品,最流行的,能力强劲的开源消息总线。ActiveMQ 是一个完全支持JMS1.1和J2EE 1.4规范的 JMS Provider实现,尽管...
  • zl18310999566
  • zl18310999566
  • 2017-01-10 14:53:08
  • 10876

<em>SpringBoot集成ActiveMQ</em>

<em>SpringBoot集成ActiveMQ</em>,ActiveMQ支持队列和主题两种消息发送方式,选择发送方式可以在<em>SpringBoot</em>的配置文件中通过参数<em>spring</em>.jms.pub-sub-domain来控制,值为false表示是...
  • 2018年04月16日 00:00

springboot集成activemq

springboot给我们的开发带了很大简便,帮住我们管理复杂的项目依赖,以springboot与activemq集成为例,在集成activemq的时候我们只需要加上一个依赖就可以了&amp;lt;d...
  • u012477338
  • u012477338
  • 2018-02-14 11:44:44
  • 122

ActiveMQ的消息重试机制

消息重发机制: 1. 处理失败 指的是MessageListener的onMessage方法里抛出RuntimeException。 2. Message头里有两个相关字段:Redelivered默认...
  • KimmKing
  • KimmKing
  • 2014-02-12 18:42:55
  • 16860

springboot整合activemq,应答模式,消息重发机制,消息持久化

准备工作: activemq的消息确认机制就是文档中说的ack机制有: AUTO_ACKNOWLEDGE = 1    自动确认 CLIENT_ACKNOWLEDGE = 2    客户端...
  • zhaoyachao123
  • zhaoyachao123
  • 2017-10-27 14:59:06
  • 1885

<em>Springboot</em>和<em>ActiveMQ</em>的整合实例

<em>Springboot</em>整合ActiveMQ <em>spring</em> boot整合activeMQ,实现ptp和topic两者消息模式 <em>SpringBoot集成ActiveMQ</em> <em>spring</em> boot整合JMS(ActiveMQ实现) <em>spring</em> boot整合JMS(...
  • 2018年04月14日 00:00

spring boot的ActiveMQ使用

消息队列能够有效的降低系统请求峰值,也能够达到解耦的效果。spring boot对MQ也有比较好的支持。本文演示spring activeMQ的使用,首先在linux安装ActiveMQ:wget h...
  • micro_hz
  • micro_hz
  • 2017-08-03 19:10:29
  • 309
    个人资料
    等级:
    访问量: 30
    积分: 40
    排名: 201万+
    文章分类
    文章存档