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

                <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;
    }





阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页