hyperf | 帶你一起看 hyperf 文檔之 amqp

date: 2019-07-17 22:42:21
title: hyperf| 帶你一起看 hyperf 文檔之 amqp

hyperf 開源有一段時(shí)間了, 從開發(fā)者交流群就能感受到熱度. 這段時(shí)間下來, 有一個(gè)明顯的現(xiàn)象, 某A 提了一個(gè)技術(shù)問題, 某B 直接拋一個(gè)官方文檔的對應(yīng)鏈接. 這種現(xiàn)象實(shí)在太常見, 甚至衍生出了 歡迎進(jìn)入 vip 交流群 這樣的商機(jī). 不得不說:

花 2 個(gè)小時(shí)認(rèn)真看一遍文檔, 比遇到問題就卡住然后到處問要高效得多.

重要的事情說三遍:

  • 認(rèn)真看一遍文檔
  • 認(rèn)真看一遍文檔
  • 認(rèn)真看一遍文檔

好了, 回到正題, 今天我們來玩 amqp.

項(xiàng)目準(zhǔn)備

這些都可以在文檔中找到, 所以直接上操作.

  • 使用開發(fā)組提供的 docker

hold 不住 docker, 不用也行, 但是要能基于開發(fā)組的 Dockerfile 配置好環(huán)境, 如果既不會(huì)用 docker, 也無法自己配置好開發(fā)環(huán)境, 請一定要努力哦.

使用 docker-compose 配置的全部環(huán)境:

version: '3'
services:
    ms:
        image: hyperf/hyperf
        volumes:
            - ../:/data
        ports:
            - "9501:9501"
        environment:
            APP_ENV: dev
        tty: true
    mysql:
        image: mysql:5.7.26
        volumes:
            - ./config/my.cnf:/etc/mysql/conf.d/my.cnf
            - ./config/sql:/docker-entrypoint-initdb.d
            - ./data/mysql:/var/lib/mysql
        ports:
            - "3306:3306"
        environment:
            TZ: Asia/Shanghai
            MYSQL_ROOT_PASSWORD: root
    redis:
        image: redis:alpine
        volumes:
            - ./config/redis.conf:/etc/redis/redis.conf
            - ./data/redis:/data
        ports:
            - "6379:6379"
    rabbitmq:
        image: rabbitmq:management-alpine
        hostname: myrabbitmq
        volumes:
            - ./data/rabbitmq:/var/lib/rabbitmq/mnesia
        ports:
            - "5672:5672" # mq
            - "15672:15672" # admin

這里多說一句, docker / Dockerfile / docker-compose 只是滿足開發(fā)環(huán)境的使用的話, 真的很簡單, 記住幾個(gè)常用的 docker 命令, 清楚 Dockerfile 幾個(gè)常用的指令(RUN CMD 等), docker-compose 只是 yaml 格式的配置文件而已.

推薦一個(gè)好習(xí)慣: 一個(gè)文檔專門記 docker / Dockerfile / docker-compose 的常用內(nèi)容, 使用過程中逐漸對這個(gè)文件進(jìn)行增刪查改(CRUD), 不用多久, 你就會(huì)發(fā)現(xiàn)自己用起 docker 來, 賊 6 !

另一個(gè)好習(xí)慣是 最佳實(shí)踐, 你要從無到有用起來很難, 但是跟著最佳實(shí)踐走, 就能又快又好 ! 當(dāng)然, 再上一層樓, 你也能成為最佳實(shí)踐.

  • 安裝項(xiàng)目
composer create-project hyperf/hyperf-skeleton hyperf-demo

安裝過程選擇自己需要的組件, 不清楚就先不要選, 反正之后可以通過 composer require 安裝. 其實(shí)我更想說的是:

安裝的組件自己 hold 不住, 然后到處叫, 這樣多沒意思呀.

  • 配置 composer.json
"repositories": {
    "hyperf": {
        "type": "path",
        "url": "../hyperf/src/*"
    },
    "packagist": {
        "type": "composer",
        "url": "https://mirrors.aliyun.com/composer"
    }
}

添加了 path, 從我本地加載 hyperf 組件, 方便開發(fā), 如果不參與 hyperf 組件開發(fā), 可以忽略這一步.

  • 添加 hyperf/amqp
# 安裝
composer require hyperf/amqp 

# 添加配置文件
php bin/hyperf.php vendor:publish hyperf/amqp
  • 修改配置, 啟動(dòng)并驗(yàn)證

我啟動(dòng)了 mysql / redis / rabbitmq, 配置相關(guān)組件的配置, 并啟動(dòng)框架進(jìn)行驗(yàn)證

# config
vim .env
vim config/autoload/redis.php
vim config/autoload/database.php
vim config/autoload/amqp.php

# test
php bin/hyperf.php start

好了, 項(xiàng)目準(zhǔn)備好了, 正式開始擼代碼.

官方文檔 amqp demo

文檔有的, 還是直接貼:

# producer
php bin/hyperf.php gen:amqp-producer DemoProducer

# consumer
php bin/hyperf.php gen:amqp-consumer DemoConsumer

# 使用 command 盜用 DemoProducer 進(jìn)行驗(yàn)證
php bin/hyperf.php gen:command TestCommand

producer 發(fā)個(gè)消息:

  • 設(shè)置 command 的名字: parent::__construct('t');
  • 使用 @Inject() 注解注入
  • 發(fā)消息, 一行搞定: $this->producer->produce(new DemoProducer('test'. date('Y-m-d H:i:s')));
<?php

declare(strict_types=1);

namespace App\Command;

use App\Amqp\Producer\DemoProducer;
use Hyperf\Amqp\Producer;
use Hyperf\Command\Command as HyperfCommand;
use Hyperf\Command\Annotation\Command;
use Hyperf\Di\Annotation\Inject;
use Psr\Container\ContainerInterface;

/**
 * @Command
 */
class TestCommand extends HyperfCommand
{
    /**
     * @var ContainerInterface
     */
    protected $container;

    /**
     * @Inject()
     * @var Producer
     */
    protected $producer;

    public function __construct(ContainerInterface $container)
    {
        $this->container = $container;

        parent::__construct('t');
    }

    public function configure()
    {
        $this->setDescription('Hyperf Demo Command');
    }

    public function handle()
    {
        $this->producer->produce(new DemoProducer('test'. date('Y-m-d H:i:s')));
    }
}

愉快的玩耍起來:

# produce
php bin/hyperf.php t

# consume
php bin/hyperf.php start # 會(huì)使用 swoole process 啟動(dòng) DemoConsumer

# 也可以訪問 rabbitmq admin 控制臺(tái)
http://localhost:15672

擼一擼 rabbitmq 官網(wǎng) tutorial

跟著 rabbitmq 官網(wǎng) tutorial, 見識一下 hyperf 中的 amqp 有多簡單

// consumer
/**
 * @Consumer()
 */
class DemoConsumer extends ConsumerMessage
{
    protected $exchange = 'hello';
    protected $type = Type::FANOUT;
    protected $queue = 'hello';

    public function consume($data): string
    {
        var_dump($data);
        return Result::ACK;
    }
}

// producer
/**
 * @Producer()
 */
class DemoProducer extends ProducerMessage
{
    protected $exchange = 'hello';
    protected $type = Type::FANOUT;
    protected $routingKey = 'hello';
    public function __construct($data)
    {
        $this->payload = $data;
    }
}

設(shè)置一下 nums 參數(shù), 就可以多進(jìn)程.

// Consumer
/**
 * @Consumer(nums=2)
 */
class DemoConsumer extends ConsumerMessage
{
    protected $exchange = 'task';
    protected $type = Type::FANOUT;
    protected $queue = 'task';

    public function consume($data): string
    {
        var_dump($data);
        return Result::ACK;
    }
}

// producer
/**
 * @Producer()
 */
class DemoProducer extends ProducerMessage
{
    protected $exchange = 'task';
    protected $type = Type::FANOUT;
    protected $routingKey = 'task';
    public function __construct($data)
    {
        $this->payload = $data;
    }
}

和上面的 hello world 一致

終于看到 routing_key 的作用了

// consumer
/**
 * @Consumer()
 */
class DemoConsumer extends ConsumerMessage
{
    protected $exchange = 'routing';
    protected $type = Type::DIRECT;
    // 這個(gè) consumer 只消費(fèi) error 級別的日志
    protected $queue = 'routing.error';
    protected $routingKey = 'error';

    public function consume($data): string
    {
        var_dump($data);
        return Result::ACK;
    }
}

/**
 * @Consumer()
 */
class Demo2Consumer extends ConsumerMessage
{
    protected $exchange = 'routing';
    protected $type = Type::DIRECT;
    // 這個(gè) consumer 消費(fèi)所有級別的日志
    protected $queue = 'routing.all';
    protected $routingKey = [
        'info',
        'warning',
        'error',
    ];

    public function consume($data): string
    {
        var_dump($data);
        return Result::ACK;
    }
}

// producer
/**
 * @Producer()
 */
class DemoProducer extends ProducerMessage
{
    protected $exchange = 'routing';
    protected $type = Type::DIRECT;
    public function __construct($data, $routingKey)
    {
        $this->routingKey = $routingKey;
        $this->payload = $data;
    }
}

// produce
$this->producer->produce(new DemoProducer('info'. date('Y-m-d H:i:s'), 'info'));
$this->producer->produce(new DemoProducer('warning'. date('Y-m-d H:i:s'), 'warning'));
$this->producer->produce(new DemoProducer('error'. date('Y-m-d H:i:s'), 'error'));
var_dump('done');

和的, 和上面的 routing 差不多

// consume
/**
 * @Consumer()
 */
class DemoConsumer extends ConsumerMessage
{
    protected $exchange = 'topics';
    protected $type = Type::TOPIC;
    protected $queue = 'topics.t1';
    // protected $routingKey = '#'; // all
    // protected $routingKey = 'kern.*';
    // protected $routingKey = '*.critical';
    // protected $routingKey = 'kern.critical';
    protected $routingKey = [
        'kern.*',
        '*.critical',
    ];

    public function consume($data): string
    {
        var_dump($data);
        return Result::ACK;
    }
}

// produce
/**
 * @Producer()
 */
class DemoProducer extends ProducerMessage
{
    protected $exchange = 'topics';
    protected $type = Type::TOPIC;
    public function __construct($data, $routingKey)
    {
        $this->routingKey = $routingKey;
        $this->payload = $data;
    }
}

可以看到, 想要用 amqp, 自動(dòng)生成好代碼后, 改一改屬性就成, so easy~

再聊 amqp

amqp 難不難用? 至少基礎(chǔ)的使用還是很好掌握的, 下面有一張圖可供參考

amqp 基礎(chǔ)使用

producer consumer connection vhost channel exchange queue routing_key bind publish consume msg 幾個(gè)概念了解了, 基礎(chǔ)使用就能很順手. 而在 hyperf 中, 得益于對一些常用使用的方式的封裝, 自動(dòng)生成代碼 + 改改類屬性 就能把 amqp 用起來 !

寫在最后

無他, 唯手熟爾.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末糠聪,一起剝皮案震驚了整個(gè)濱河市白指,隨后出現(xiàn)的幾起案子截粗,更是在濱河造成了極大的恐慌森缠,老刑警劉巖访忿,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異是牢,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)陕截,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進(jìn)店門驳棱,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人农曲,你說我怎么就攤上這事社搅。” “怎么了乳规?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵形葬,是天一觀的道長。 經(jīng)常有香客問我暮的,道長笙以,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任青扔,我火速辦了婚禮源织,結(jié)果婚禮上翩伪,老公的妹妹穿的比我還像新娘微猖。我一直安慰自己,他們只是感情好缘屹,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布凛剥。 她就那樣靜靜地躺著,像睡著了一般轻姿。 火紅的嫁衣襯著肌膚如雪犁珠。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天互亮,我揣著相機(jī)與錄音犁享,去河邊找鬼。 笑死豹休,一個(gè)胖子當(dāng)著我的面吹牛炊昆,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播威根,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼凤巨,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了洛搀?” 一聲冷哼從身側(cè)響起敢茁,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎留美,沒想到半個(gè)月后彰檬,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體伸刃,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年逢倍,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了奕枝。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,040評論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡瓶堕,死狀恐怖隘道,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情郎笆,我是刑警寧澤谭梗,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站宛蚓,受9級特大地震影響激捏,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜凄吏,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一远舅、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧痕钢,春花似錦图柏、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至随抠,卻和暖如春裁着,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背拱她。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工二驰, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人秉沼。 一個(gè)月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓桶雀,卻偏偏與公主長得像,于是被迫代替她去往敵國和親氧猬。 傳聞我的和親對象是個(gè)殘疾皇子背犯,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評論 2 355