(三)Spring整合RabbitMQ&SpringBoot 整合RabbitMQ&RabbitMQ 镜像队列

Spring整合RabbitMQ:

SpringBoot 整合RabbitMQ:

RabbitMQ 镜像队列:(待补充)

-------------------------------

Spring整合RabbitMQ:

整合demo 如下:

demo:

1.加上POM文件:

     

public class TulingMsgDelegate {


    public void handleMessage(String msgBody) {
        System.out.println("TulingMsgDelegate。。。。。。handleMessage"+msgBody);
    }

    public void consumerMsg(String msg){
        System.out.println("TulingMsgDelegate。。。。。。consumerMsg"+msg);
    }

    public void consumerTopicQueue(String msgBody) {
        System.out.println("TulingMsgDelegate。。。。。。consumerTopicQueue"+msgBody);

    }

    public void consumerTopicQueue2(String msgBody) {
        System.out.println("TulingMsgDelegate。。。。。。consumerTopicQueue2"+msgBody);

    }

    /**
     * 处理json
     * @param jsonMap
     */
    public void consumerJsonMessage(Map jsonMap) {
        System.out.println("TulingMsgDelegate ============================处理json"+jsonMap);
    }

    /**
     * 处理order得
     * @param order
     */
    public void consumerJavaObjMessage(Order order) {
        System.out.println("TulingMsgDelegate ============================处理java对象"+order.toString());

    }



    public void consumerFileMessage(File file) {
        System.out.println("TulingMsgDelegate========================处理文件"+file.getName());
    }
}

消费者容器,监听多个队列,设置多个Queue,多写几个。监听我们的文件,设置消费者最大消费者数量,设置最大数值的消费者数量签收模式;是自动还是手动的。然后设置拒绝重回队列。创建我们消息的监听器,使用默认的监听方法,代码如下:

@Test
	public void testRabbitmqTemplate() {

		MessageProperties messageProperties = new MessageProperties();
		messageProperties.getHeaders().put("company","tuling");
		messageProperties.getHeaders().put("name","smlz");

		String msgBody = "hello tuling";
		Message message = new Message(msgBody.getBytes(),messageProperties);

		//rabbitTemplate.send("tuling.topic.exchange","topic.haha",message);

		//不需要message对象发送
		rabbitTemplate.convertAndSend("tuling.direct.exchange","direct.key","smlz");
	}

消费者方法,接受的第一种用法,其实有很多很简单的,其实使用很多的Springboot设置更简单。

真正开发中非常简单的,启动工程,发送信息,说明拦截掉了,然后呢,

制定方法,具体的某一个队列被某一个消费者消费,制定消费方法,setDefalutMessage()方法。重启一下,我们不同的队列,不同的方法消费,queue new 一个hashmap 的方法,

        //指定具体某一个队列被某一个消费者消费
/*        Map<String,String> queueOrTagToMethodName = new HashMap<>();
        queueOrTagToMethodName.put("testTopicQueue","consumerTopicQueue");
        queueOrTagToMethodName.put("testTopicQueue2","consumerTopicQueue2");
        messageListenerAdapter.setQueueOrTagToMethodName(queueOrTagToMethodName);*/

测试方法:

	@Test
	public void messageListenerAdaperQueueOrTagToMethodName(){
		rabbitTemplate.convertAndSend("tuling.topic.exchange","topic.xixi","你好 图灵");
		rabbitTemplate.convertAndSend("tuling.topic.exchange","topic.key.xixi","你好 ");
	}

创建一个quenrTopic Queue,制定一个队列的方法,监听另外一个方法,来这儿方法,设置

队列消费和绑定,listener 把,把工程给起起来,然后这边测试,发生的事情,同样;有一条信息luyo

路由到这边的高级的。一直Spring类型的,JSON的,Object 方法,处理JSON的,中间的方法处理JSON的。

然后把接着把new 一个JSON转换器的方法,这个设置,人家底层处理的使用Map 来接受的,通发送处理JSON

配置文件:

/**
         * 处理json
         * 1:需要创建一个消息转换器对象
         * 2:把消息转换器设置到消息监听适配器上
         * 3:把监听器设置到容器中

        messageListenerAdapter.setDefaultListenerMethod("consumerJsonMessage");
        Jackson2JsonMessageConverter jackson2JsonMessageConverter = new Jackson2JsonMessageConverter();
        messageListenerAdapter.setMessageConverter(jackson2JsonMessageConverter);
        simpleMessageListenerContainer.setMessageListener(messageListenerAdapter);
         */

通过消息属性体方法,这是处理JSON的,发送我们java Object 的处理的方法,处理Java 对象的。其中有少许的不同。

setfault 方法,设置处理的方法,设置我们的消息转换器方法,new 一个JSON 类对象转化的方法

@Test
	public void sendJson() throws JsonProcessingException {

		Order order = new Order();
		order.setOrderNo(UUID.randomUUID().toString());
		order.setCreateDt(new Date());
		order.setPayMoney(10000.00);
		order.setUserName("smlz");

		ObjectMapper objectMapper = new ObjectMapper();
		String orderJson = objectMapper.writeValueAsString(order);

		MessageProperties messageProperties = new MessageProperties();
		messageProperties.setContentType("application/json");
		Message orderMsg = new Message(orderJson.getBytes(),messageProperties);
		rabbitTemplate.convertAndSend("tuling.direct.exchange","rabbitmq.order",orderMsg);

	}

不信任的信息,Java 最终把我们的LIstenAdapter ,

发送端:

@Test
	public void sendJavaObj() throws JsonProcessingException {

		Order order = new Order();
		order.setOrderNo(UUID.randomUUID().toString());
		order.setCreateDt(new Date());
		order.setPayMoney(10000.00);
		order.setUserName("smlz");

		ObjectMapper objectMapper = new ObjectMapper();
		String orderJson = objectMapper.writeValueAsString(order);

		MessageProperties messageProperties = new MessageProperties();
		messageProperties.setContentType("application/json");
		messageProperties.getHeaders().put("__TypeId__","com.tuling.entity.Order");
		Message orderMsg = new Message(orderJson.getBytes(),messageProperties);
		rabbitTemplate.convertAndSend("tuling.direct.exchange","rabbitmq.order",orderMsg);

	}

标记一个数值的方法,序列化和反序列化的方法,测试我们发送得java 对象的方法:

看一下的一个是ListAdapter方法,创建一个DefalutJackJSON ,找一下错误的原因的方法,JSON的

方法,

//设置java 转JSON的

试一下,把文字,图片发到MQ写出来,创建到一个方法,时间的方法,consumer方法,

设置转换器的方法,new一个messageconvert 方法,//设置转换器方法,把代码的跑起来的方法,

也可以发一个图片,进行发送测试:

 /**
         * 处理pdf  image 等等
         */
        messageListenerAdapter.setDefaultListenerMethod("consumerFileMessage");
        //全局转换器
        ContentTypeDelegatingMessageConverter messageConverter = new ContentTypeDelegatingMessageConverter();
        messageConverter.addDelegate("img/png", new TulingImageConverter());
        messageConverter.addDelegate("img/jpg",new TulingImageConverter());
        messageConverter.addDelegate("application/word",new TulingWordConverter());
        messageConverter.addDelegate("word",new TulingWordConverter());


        messageListenerAdapter.setMessageConverter(messageConverter);
        simpleMessageListenerContainer.setMessageListener(messageListenerAdapter);


        return simpleMessageListenerContainer;
    }

也可以发送一个文档,进行测试:

测试案例如下:

@Test
	public void sendImage() throws IOException {
		byte[] imgBody = Files.readAllBytes(Paths.get("D:/smlz/file01","smlz.png"));
		MessageProperties messageProperties = new MessageProperties();
		messageProperties.setContentType("img/png");
		Message message = new Message(imgBody, messageProperties);
		rabbitTemplate.send("tuling.direct.exchange","rabbitmq.file",message);

	}

	@Test
	public void sendWord() throws IOException {
		byte[] imgBody = Files.readAllBytes(Paths.get("D:/smlz/file01","spring.docx"));
		MessageProperties messageProperties = new MessageProperties();
		messageProperties.setContentType("application/word");
		Message message = new Message(imgBody, messageProperties);
		rabbitTemplate.send("tuling.direct.exchange","rabbitmq.file",message);

	}

下载延时插件:

@Bean

测试发送延迟插件:

https://blog.csdn.net/joy_pan/article/details/90600642

-----------------------

SpringBoot 整合RabbitMQ:

1.加载POM文件:

<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-amqp</artifactId>
		</dependency>

参考博文:https://blog.csdn.net/qq_35387940/article/details/100514134

我们来看一下配置文件,:

消费端: 导入一个包,另外一个东西,配置签收模式的,线程最大并发数目是10,new messagePostProcess,延迟10s 种

清空一下,发送延时消息,发送延插件消息,Spring 提供的

分布式事务,同一个事务中,CTL调用我们的Serc中,消息实体,然后保存到我们的数据库,两点,同一个事务中,如果我抛出异常, 消息不会发送,这是在同一个事务中,saveOrderInfo 中,业务都保存下来,消息没有发送出去,回调我们的错误的状态,看一下消息状态,定时任务会把消息更新重试次数再次发哦少年宫,生产端都细发送。

设置消息转换器,起作用了,设置我们生产端的方法,组件不清楚的话,看下Spring,

看一下消费端的代码:

 @RabbitListener(queues = {ORDER_TO_PRODUCT_QUEUE_NAME})
    @RabbitHandler
    public void consumerMsgWithLock(Message message, Channel channel) throws IOException {

        ObjectMapper objectMapper = new ObjectMapper();
        MsgTxtBo msgTxtBo = objectMapper.readValue(message.getBody(), MsgTxtBo.class);
        Long deliveryTag = (Long) message.getMessageProperties().getDeliveryTag();

        if (redisTemplate.opsForValue().setIfAbsent(LOCK_KEY + msgTxtBo.getMsgId(), msgTxtBo.getMsgId())) {
            log.info("消费消息:{}", msgTxtBo);
            try {
                //更新消息表也业务表
                productService.updateProductStore(msgTxtBo);
                //消息签收
                System.out.println(1/0);
                channel.basicAck(deliveryTag, false);
            } catch (Exception e) {
                /**
                 * 更新数据库异常说明业务没有操作成功需要删除分布式锁
                 */
                if (e instanceof BizExp) {
                    BizExp bizExp = (BizExp) e;
                    log.info("数据业务异常:{},即将删除分布式锁", bizExp.getErrMsg());
                    //删除分布式锁
                    redisTemplate.delete(LOCK_KEY);
                }

                //更新消息表状态
                MessageContent messageContent = new MessageContent();
                messageContent.setMsgStatus(MsgStatusEnum.CONSUMER_FAIL.getCode());
                messageContent.setUpdateTime(new Date());
                messageContent.setErrCause(e.getMessage());
                messageContent.setMsgId(msgTxtBo.getMsgId());
                msgContentMapper.updateMsgStatus(messageContent);
                channel.basicReject(deliveryTag,false);
            }

        } else {
            log.warn("请不要重复消费消息{}", msgTxtBo);
            channel.basicReject(deliveryTag,false);
        }

    }

我是在这个服务上加上一个服务的,加上一个数据异常,模拟更新,

把消费者启动,消息表没哟了,保存订单,插入消息表,定时任务去扫表。事务回滚了,

由于是业务异常,更新库存报异常,所以说是没有问题的,把product 关掉,模拟另外一个

抛出异常,模拟网络闪断,业务员正常之后,模拟网络抖动,

上了三节课的资料,模拟网络抖动,生产端跑起来之后,定时任务去扫描,通过我们的redis 命令,处理我们任务,

假如说业务抛出异常之后,封装了异常类型,失败,把锁给删除了。进步了,把锁给删除了。如果不是业务异常,模拟网络抖动,业务数据已经更新过了,更新状态下次重发就进不来,模拟网络抖动,唯一性锁的约束,现在模拟一下,现在我们把product 重启,如果分布式锁,确实可以做到,同学就数据库更能挂,现在处理1,始终只扣一个,加上服务。

我们会发送我们的消费端,UUID,传过来之后,消息之后,CorrlaionData 给我们生产端,那就根据ID更新的。

代码:

rabbitmq 镜像队列:

现在一个raabiitmq 如何做集群呢?

现在能配置3个节点的集群,启动之后,执行集群命令,

但是同步会同步到集群,镜像队列,集群同步之后,不支持集群的方法,

开启分析,启动我们的Down机的话,发送我们的集群信息,成功了,重启一下,监听到我们的消费,换了几台之后,集群模式,

集群的命令:

rabbitmqctl stop_all

rabbitmqctl  join

参考博文:

https://blog.csdn.net/qq_18483301/article/details/90268453

https://blog.csdn.net/fall_hat/article/details/104980971

https://blog.csdn.net/zhanglong_longlong/article/details/78262459

发布了668 篇原创文章 · 获赞 12 · 访问量 12万+

猜你喜欢

转载自blog.csdn.net/xiamaocheng/article/details/105178300