rabbitmq

发送方:

1, 不关注队列是否存在,如果交换机直接这边生成了,也没有在这边做绑定啥的,那么mq那里是没有这个交换机的,要发送个请求,才会出来,如果在出来之前消费者服务启动是会报错,绑定不到交换机,进程挂掉(如果消费者也生成交换机,然后用bing绑定,交换机会立刻出来,并绑定成功)
2,如果没有交换机,也不会报错,不会影响启动,只有在调用的时候会报错,找不到交换机
3,如果已经存在交换机,发送的时候又从新定义此交换机的参数,会报错。发送会使用这次定义的属性,但是mq中的交换机不会变。所以会报错,发送跟交换机的属性不一样,重试几次之后,就不会发送了,发送失败。
消费方:

1,如果绑定的交换机不存在,会报错,并且进程都起不来
2,如果绑定好不是默认的交换机后,交换机删除了,那么此队列会变成绑定默认队列,如果交换机在生成了,队列还是绑定的默认。如果再次绑定但是改变了队列信息,会报错,说队列信息不一样。如果没有改变信息,再次绑定,此队列会重新绑定到这个交换机
3,队列如果存在(交换机在存在),在从新绑定,如果只改变rootingkey那就是2个,如果是只改变队列信息,会报错2个队列信息不一样

    //解绑 队列与交换机
    @Test
    public void unBind() throws Exception {
        Connection connection = ConnectionUtil.getConnection();
        Channel channel = connection.createChannel();
        channel.queueUnbind("spring.test.*", "spring.test.exchange", "*.*");
    }
    // 设置到broker的确认(即是否到达exchange)         
    springbootConnectionFactory.setPublisherConfirmType(
                        CachingConnectionFactory.ConfirmType.CORRELATED);
    // 没有队列接收不会触发这个,只有当异常时才会触发
    springbootConnectionFactory.setPublisherReturns(true); 
    factory.addChannelListener(rabbitChannelListener);
    factory.addConnectionListener(rabbitConnectionListener);
    factory.setRecoveryListener(rabbitRecoveryListener);

    // 交换器无法根据自身类型和路由键找到一个符合条件的队列时的处理方式 true:RabbitMQ会调用 
    // Basic.Return命令将消息返回给生产者 false:RabbitMQ会把消息直接丢弃
    rabbitTemplate.setMandatory(true);
这里有三个监听器:
ChannelListener 用于监听通道的创建和销毁
     @Service
    public class RabbitChannelListener implements ChannelListener {
        @Override
        public void onCreate(Channel channel, boolean b) {
            log.info("=====onCreate channel: {}, transactional: {}", channel, b);
        }

        @Override
        public void onShutDown(ShutdownSignalException signal) {
            // 可根据isHardError判断是channel断开还是connection断开
            if (signal.isHardError()) {
                AMQImpl.Connection.Close close = (AMQImpl.Connection.Close) signal.getReason();
                log.warn("Connection onShutDown replyCode: {}, methodId: {}, classId: {}, replyText: {}",
                        close.getReplyCode(), close.getMethodId(), close.getClassId(), close.getReplyText());
            } else {
                AMQImpl.Channel.Close close = (AMQImpl.Channel.Close) signal.getReason();
                log.warn("Channel onShutDown replyCode: {}, methodId: {}, classId: {}, replyText: {}",
                        close.getReplyCode(), close.getMethodId(), close.getClassId(), close.getReplyText());
            }
        }
    }

ConnectionListener 用于监听连接的创建和关闭

    public class RabbitConnectionListener implements ConnectionListener {
        @Override
        public void onCreate(Connection connection) {
            log.info("================onCreate: {}", connection);
        }

        @Override
        public void onClose(Connection connection) {
            log.info("================onClose: {}", connection);
        }

        @Override
        public void onShutDown(ShutdownSignalException signal) {
            log.info("================onShutDown: {}", signal);
        }
    }
RecoveryListener 监听自动重连的情况,这个listener没有测试出在什么场景会出现
    public class RabbitRecoveryListener implements RecoveryListener {
        @Override
        public void handleRecovery(Recoverable recoverable) {
            log.info("================handleRecovery: {}", recoverable);
        }

        @Override
        public void handleRecoveryStarted(Recoverable recoverable) {
            log.info("================handleRecoveryStarted: {}", recoverable);
        }
    }

当生产者和消费者在同一个服务里面,官方文档特别提醒,不要使用同一个factory
1,可以创建2个factory
2,//使用单独的发送连接,避免生产者由于各种原因阻塞而导致消费者同样阻塞
rabbitTemplate.setUsePublisherConnection(true);

关于失败重连模式
1,也可以调用对应的类对象,实现重连。比如java client 方法
ConnectionFactory factory = new ConnectionFactory();
factory.setAutomaticRecoveryEnabled(true); //设置网络异常重连
factory.setNetworkRecoveryInterval(10000);//设置 没10s ,重试一次
factory.setTopologyRecoveryEnabled(true);//设置重新声明交换器,队列等信息。
2,最简单方式,捕获异常,判断异常信息,重新连接。try.....,except,(catch)。
下面设置ssl里面的factory就是使用的这种


设置 ssl:

    @Bean(name = "cachingConnectionFactory")
    public ConnectionFactory cachingConnectionFactory(MqProperties mqProperties) {
        log.info("mq ssl open:{}", mqProperties.getMqSslOpen());
        CachingConnectionFactory springbootConnectionFactory = new CachingConnectionFactory(
                getCommonConnectionFactory());
        try {
            Map<String, String> map = getMqInfo(mqProperties);
            springbootConnectionFactory.setHost(map.get("mqIp"));
            springbootConnectionFactory.setPort(Integer.parseInt(map.get("mqPort")));
            springbootConnectionFactory.setUsername(map.get("mqUser"));
            springbootConnectionFactory.setPassword(map.get("mqPwd"));
            log.info("mqConnectionFactory created, mq address is :{},port is {}", springbootConnectionFactory.getHost(),
                    springbootConnectionFactory.getPort());
            Connection connection = springbootConnectionFactory.createConnection();
            connection.close();
            return springbootConnectionFactory;
        } catch (Exception e) {
            log.info("create rabbitMq connection error:{}", e.getMessage());
        }
        new Thread(() -> System.exit(1)).start();
        return null;
    }

    private com.rabbitmq.client.ConnectionFactory getCommonConnectionFactory() {
        com.rabbitmq.client.ConnectionFactory rabbitConnectionFactory = new com.rabbitmq.client.ConnectionFactory();
        rabbitConnectionFactory.setVirtualHost("/");
        rabbitConnectionFactory.useSslProtocol(getSslContext().orElseThrow(RuntimeException::new));
        return rabbitConnectionFactory;
    }

    private Optional<SSLContext> getSslContext(MqProperties mqProperties) {
        ClassLoader classLoader = MqProperties.class.getClassLoader();
        if (classLoader == null) {
            return Optional.empty();
        }
        try (InputStream trustStoreStream = classLoader.getResourceAsStream("XXXX.jks")) {
            return sslContext(trustStoreStream, mqProperties.getMqTrustPass(), mqProperties.getProtocol());
        } catch (Exception e) {
            log.error("getSslContext error:", e);
        }
        return Optional.empty();
    }

    private Optional<SSLContext> sslContext(InputStream trustStoreStream, String mqTrustPass, String protocol)
            throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException, KeyManagementException {
        char[] trustPassphrase = 解密出这个值(mqTrustPass).toCharArray();
        KeyStore tks = KeyStore.getInstance("JKS");
        tks.load(trustStoreStream, trustPassphrase);
        TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
        tmf.init(tks);
        // 初始化SSL上下文
        SSLContext sslContext = SSLContext.getInstance(protocol);
        sslContext.init(null, tmf.getTrustManagers(), null);
        return Optional.of(sslContext);
    }
    
    @Bean
    public RabbitTemplate rabbitTemplate(@Qualifier("cachingConnectionFactory") ConnectionFactory connectionFactory) {
        RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
        rabbitTemplate.setConfirmCallback(((correlationData, ack, cause) -> {
            if (!ack) {
                log.error("correlationData:{} ack:false cause:{} ", correlationData, cause);
            }
        }));
        return rabbitTemplate;
    }

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值