RabbitMQ筆記十七: Alternate Exchange

Alternate Exchange

Rabbitmq自己擴(kuò)展的功能熙宇,不是AMQP協(xié)議定義的。
Alternate Exchange屬性的作用呼盆,創(chuàng)建Exchange指定該ExchangeAlternate Exchange屬性擂达,發(fā)送消息的時(shí)候根據(jù)route key并沒(méi)有把消息路由到隊(duì)列中去,這就會(huì)將此消息路由到Alternate Exchange屬性指定的Exchange上了出刷。

創(chuàng)建一個(gè)Fanout類型的Exchange

自動(dòng)聲明帶有Alternate Exchange的Exchange,

import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.Exchange;
import org.springframework.amqp.core.TopicExchange;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.HashMap;
import java.util.Map;

@Configuration
public class MQConfig {

    @Bean
    public ConnectionFactory connectionFactory(){
        CachingConnectionFactory factory = new CachingConnectionFactory();
        factory.setUri("amqp://zhihao.miao:123456@192.168.1.131:5672");
        return factory;
    }

    @Bean
    public RabbitAdmin rabbitAdmin(ConnectionFactory connectionFactory){
        RabbitAdmin rabbitAdmin = new RabbitAdmin(connectionFactory);
        return rabbitAdmin;
    }

    @Bean
    public Exchange exchange(){
        Map<String,Object> argsMap = new HashMap<>();
        argsMap.put("alternate-exchange","zhihao.miao.exchange.order");
        return new TopicExchange("zhihao.miao.exchange.pay",true,false,argsMap);
    }


     @Bean
    public Binding binding(){
        return new Binding("zhihao.miao.pay",Binding.DestinationType.QUEUE,"zhihao.miao.exchange.pay","zhihao.miao.pay.*",new HashMap<>());
    }

    @Bean
    public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory){
        RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
        return rabbitTemplate;
    }
}

應(yīng)用啟動(dòng)類

import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;

@ComponentScan
public class Application {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Application.class);
        //使得客戶端第一次連接rabbitmq
        context.getBean(RabbitAdmin.class).getQueueProperties("**");
        context.close();
    }
}

啟動(dòng)應(yīng)用啟動(dòng)類之后生成一個(gè)帶有alternate-exchange屬性的Exchange坯辩。

生成了一個(gè)帶有alternate-exchange屬性的Exchange

zhihao.miao.exchange.pay是個(gè)包含alternate-exchange屬性的topic類型的exchange(route key是zhihao.miao.pay.*馁龟,隊(duì)列名是zhihao.miao.pay),alternate-exchange屬性指定的是fanout類型的exchange,exchange的名稱是zhihao.miao.exchange.order(綁定到zhihao.miao.order隊(duì)列)

如果正確的路由(符合zhihao.miao.pay.*)規(guī)則漆魔,則zhihao.miao.pay隊(duì)列接收到消息坷檩。如果是不正確的路由(不符合zhihao.miao.pay.*)規(guī)則,則路由到zhihao.miao.exchange.pay Exchange指定的alternate-exchange屬性的Exchange中有送。

測(cè)試

import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MQConfig {

    @Bean
    public ConnectionFactory connectionFactory(){
        CachingConnectionFactory factory = new CachingConnectionFactory();
        factory.setUri("amqp://zhihao.miao:123456@192.168.1.131:5672");
        return factory;
    }

    @Bean
    public RabbitAdmin rabbitAdmin(ConnectionFactory connectionFactory){
        RabbitAdmin rabbitAdmin = new RabbitAdmin(connectionFactory);
        return rabbitAdmin;
    }

    @Bean
    public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory){
        RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
        return rabbitTemplate;
    }
}

啟動(dòng)應(yīng)用類:

import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;

import java.util.concurrent.TimeUnit;

@ComponentScan
public class Application {
    public static void main(String[] args) throws Exception{
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Application.class);
        RabbitTemplate rabbitTemplate = context.getBean(RabbitTemplate.class);
        System.out.println(rabbitTemplate);

        byte[] body = "hello,zhihao.miao".getBytes();

        MessageProperties messageProperties = new MessageProperties();
        messageProperties.setContentType("json");

        Message message = new Message(body,messageProperties);

        rabbitTemplate.send("zhihao.miao.exchange.pay","zhihao.miao.pay.aaa",message);

        TimeUnit.SECONDS.sleep(3);

        context.close();
    }
}

此時(shí)發(fā)送消息到名為zhihao.miao.exchange.payExchange淌喻,而Route keyzhihao.miao.pay.aaa僧家,所以能正確地路由到zhihao.miao.pay隊(duì)列中雀摘。

當(dāng)指定的Route key不能正確的路由的時(shí)候,則直接發(fā)送到名為zhihao.miao.exchange.orderExchange八拱,而因?yàn)槲覀兌x的Exchange類型是fanout類型阵赠,所以就能路由到zhihao.miao.order隊(duì)列中了涯塔。

import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;

import java.util.concurrent.TimeUnit;

@ComponentScan
public class Application {
    public static void main(String[] args) throws Exception{
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Application.class);
        RabbitTemplate rabbitTemplate = context.getBean(RabbitTemplate.class);
        System.out.println(rabbitTemplate);

        byte[] body = "hello,zhihao.miao".getBytes();

        MessageProperties messageProperties = new MessageProperties();
        messageProperties.setContentType("json");

        Message message = new Message(body,messageProperties);

        //此時(shí)route不到,那么就路由到alternate-exchange的屬性配置的exchage
        rabbitTemplate.send("zhihao.miao.exchange.pay","hehe.zhihao.miao",message);

        TimeUnit.SECONDS.sleep(3);

        context.close();
    }
}

一般alternate-exchange屬性的值最好是fanout類型的exchange清蚀,否則還會(huì)根據(jù)route keyalternate-exchange屬性的exchange進(jìn)行匹配再去路由匕荸。而如果指定了fanout類型的exchange,不需要去匹配routekey枷邪。

alternate-exchange配置的Exchange也不能正確路由

示列說(shuō)明

創(chuàng)建了一個(gè)topic類型的Exchange帶有alternate-exchange屬性榛搔,其alternate-exchangeexchange也是topic類型的exchange,如果消息的route key既不能,這個(gè)消息就會(huì)丟失东揣〖螅可以觸發(fā)publish confirm機(jī)制,表示這個(gè)消息沒(méi)有確認(rèn)嘶卧。

創(chuàng)建Exchange
binding關(guān)系
binding關(guān)系

配置:

import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MQConfig {

    @Bean
    public ConnectionFactory connectionFactory(){
        CachingConnectionFactory factory = new CachingConnectionFactory();
        factory.setUri("amqp://zhihao.miao:123456@192.168.1.131:5672");
        return factory;
    }

    @Bean
    public RabbitAdmin rabbitAdmin(ConnectionFactory connectionFactory){
        RabbitAdmin rabbitAdmin = new RabbitAdmin(connectionFactory);
        return rabbitAdmin;
    }

    @Bean
    public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory){
        RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
        return rabbitTemplate;
    }
}

正常路由到Exchange名為head.info路由的隊(duì)列中尔觉。

import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;

import java.util.concurrent.TimeUnit;

@ComponentScan
public class Application {
    public static void main(String[] args) throws Exception{
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Application.class);
        RabbitTemplate rabbitTemplate = context.getBean(RabbitTemplate.class);
        System.out.println(rabbitTemplate);

        byte[] body = "hello,zhihao.miao".getBytes();

        MessageProperties messageProperties = new MessageProperties();
        messageProperties.setContentType("json");

        Message message = new Message(body,messageProperties);

        //正確路由到header.info隊(duì)列
        rabbitTemplate.send("head.info","head.info.a",message);

        TimeUnit.SECONDS.sleep(3);

        context.close();
    }
}

路由到Exchange名為head.info指定的alternate-exchange配置的head.error所路由的隊(duì)列中。

import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;

import java.util.concurrent.TimeUnit;

@ComponentScan
public class Application {
    public static void main(String[] args) throws Exception{
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Application.class);
        RabbitTemplate rabbitTemplate = context.getBean(RabbitTemplate.class);
        System.out.println(rabbitTemplate);

        byte[] body = "hello,zhihao.miao".getBytes();

        MessageProperties messageProperties = new MessageProperties();
        messageProperties.setContentType("json");

        Message message = new Message(body,messageProperties);

        //正確路由到header.info隊(duì)列
        rabbitTemplate.send("head.info","head.error.a",message);

        TimeUnit.SECONDS.sleep(3);

        context.close();
    }
}

二者都不符合則消息丟失芥吟,可以使用publish confirm來(lái)做生產(chǎn)端的消息確認(rèn),因?yàn)橄](méi)有正確路由到隊(duì)列侦铜,所以觸發(fā)了return method。

import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;

import java.util.concurrent.TimeUnit;

@ComponentScan
public class Application {
    public static void main(String[] args) throws Exception{
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Application.class);
        RabbitTemplate rabbitTemplate = context.getBean(RabbitTemplate.class);
        System.out.println(rabbitTemplate);

        byte[] body = "hello".getBytes();

        MessageProperties messageProperties = new MessageProperties();
        messageProperties.setContentType("json");

        Message message = new Message(body,messageProperties);

        //正確路由到header.info隊(duì)列
        rabbitTemplate.send("head.info","header.debug.a",message);

        TimeUnit.SECONDS.sleep(30);

        context.close();
    }
}

配置:

import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MQConfig {

    @Bean
    public ConnectionFactory connectionFactory(){
        CachingConnectionFactory factory = new CachingConnectionFactory();
        factory.setUri("amqp://zhihao.miao:123456@192.168.1.131:5672");
        factory.setPublisherReturns(true);
        return factory;
    }

    @Bean
    public RabbitAdmin rabbitAdmin(ConnectionFactory connectionFactory){
        RabbitAdmin rabbitAdmin = new RabbitAdmin(connectionFactory);
        return rabbitAdmin;
    }

    @Bean
    public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory){
        RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
        rabbitTemplate.setMandatory(true);
        rabbitTemplate.setReturnCallback((message, replyCode, replyText, exchange, routingKey) -> {
            System.out.println("===========消息無(wú)法被路由=========");
            System.out.println("replyCode: "+replyCode);
            System.out.println("replyText: "+replyText);
            System.out.println("exchange: "+exchange);
            System.out.println("routingKey: "+routingKey);
        });
        return rabbitTemplate;
    }
}

總結(jié)

  • 建議Alternate Exchange的類型是fanout钟鸵,防止出現(xiàn)路由失敗钉稍。
    fanout exchange一般不需要指定Alternate Exchange屬性。
  • 如果一個(gè)Exchange指定了Alternate Exchange棺耍,那就意味著嫁盲,當(dāng)ExchangeAlternate Exchange都無(wú)法路由的時(shí)候,才會(huì)觸發(fā)return method烈掠。

參考資料

Alternate Exchange官網(wǎng)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末羞秤,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子左敌,更是在濱河造成了極大的恐慌瘾蛋,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,695評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件矫限,死亡現(xiàn)場(chǎng)離奇詭異哺哼,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)叼风,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,569評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門取董,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人无宿,你說(shuō)我怎么就攤上這事茵汰。” “怎么了孽鸡?”我有些...
    開(kāi)封第一講書人閱讀 168,130評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵蹂午,是天一觀的道長(zhǎng)栏豺。 經(jīng)常有香客問(wèn)我,道長(zhǎng)豆胸,這世上最難降的妖魔是什么奥洼? 我笑而不...
    開(kāi)封第一講書人閱讀 59,648評(píng)論 1 297
  • 正文 為了忘掉前任,我火速辦了婚禮晚胡,結(jié)果婚禮上灵奖,老公的妹妹穿的比我還像新娘。我一直安慰自己估盘,他們只是感情好桑寨,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,655評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著忿檩,像睡著了一般尉尾。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上燥透,一...
    開(kāi)封第一講書人閱讀 52,268評(píng)論 1 309
  • 那天沙咏,我揣著相機(jī)與錄音,去河邊找鬼班套。 笑死肢藐,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的吱韭。 我是一名探鬼主播吆豹,決...
    沈念sama閱讀 40,835評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼理盆!你這毒婦竟也來(lái)了痘煤?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 39,740評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤猿规,失蹤者是張志新(化名)和其女友劉穎衷快,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體姨俩,經(jīng)...
    沈念sama閱讀 46,286評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡蘸拔,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,375評(píng)論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了环葵。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片调窍。...
    茶點(diǎn)故事閱讀 40,505評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖张遭,靈堂內(nèi)的尸體忽然破棺而出邓萨,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 36,185評(píng)論 5 350
  • 正文 年R本政府宣布先誉,位于F島的核電站,受9級(jí)特大地震影響的烁,放射性物質(zhì)發(fā)生泄漏褐耳。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,873評(píng)論 3 333
  • 文/蒙蒙 一渴庆、第九天 我趴在偏房一處隱蔽的房頂上張望铃芦。 院中可真熱鬧,春花似錦襟雷、人聲如沸刃滓。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 32,357評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)咧虎。三九已至,卻和暖如春计呈,著一層夾襖步出監(jiān)牢的瞬間砰诵,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,466評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工捌显, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留茁彭,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,921評(píng)論 3 376
  • 正文 我出身青樓扶歪,卻偏偏與公主長(zhǎng)得像理肺,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子善镰,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,515評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理妹萨,服務(wù)發(fā)現(xiàn),斷路器炫欺,智...
    卡卡羅2017閱讀 134,701評(píng)論 18 139
  • Dead Letter Exchange 在隊(duì)列上指定一個(gè)Exchange眠副,則在該隊(duì)列上發(fā)生如下情況,1.消息被拒...
    二月_春風(fēng)閱讀 9,525評(píng)論 0 4
  • 來(lái)源 RabbitMQ是用Erlang實(shí)現(xiàn)的一個(gè)高并發(fā)高可靠AMQP消息隊(duì)列服務(wù)器竣稽。支持消息的持久化囱怕、事務(wù)、擁塞控...
    jiangmo閱讀 10,367評(píng)論 2 34
  • Exchange概念 Exchange:交互機(jī)毫别,根據(jù)路由鍵轉(zhuǎn)發(fā)消息到綁定的隊(duì)列娃弓。 自己說(shuō)說(shuō)Exchange在Rab...
    二月_春風(fēng)閱讀 22,705評(píng)論 1 20
  • 今天繼續(xù)培訓(xùn),繼昨天核心詞匯與客戶感知外岛宦,今天做了成功五步驟台丛,銷售技巧,消費(fèi)心理及品牌價(jià)值及理念的培訓(xùn),下午還考試...
    橋上橋樹(shù)閱讀 268評(píng)論 0 0