hyperf從零開(kāi)始構(gòu)建微服務(wù)(二)——構(gòu)建服務(wù)消費(fèi)者

閱讀目錄

我們說(shuō)過(guò),服務(wù)提供者可以提供各種服務(wù),它可以和數(shù)據(jù)庫(kù)進(jìn)行交互;服務(wù)消費(fèi)者是純消費(fèi)的服務(wù)批什,只需要遠(yuǎn)程訪問(wèn)服務(wù)提供者即可屠凶。

下面我們按步驟構(gòu)建消費(fèi)者模塊窜护。

源碼已上傳至github睡腿,https://github.com/bailangzhan/hyperf-rpc

1、構(gòu)建服務(wù)消費(fèi)者

除了對(duì)時(shí)區(qū)進(jìn)行設(shè)置爷光,其他的組件暫時(shí)都不安裝垫竞,選擇“n”即可。

composer create-project hyperf/hyperf-skeleton shop_consumer_user 
Creating a "hyperf/hyperf-skeleton" project at "./shop_consumer_user"
Installing hyperf/hyperf-skeleton (v2.2.1)
  - Installing hyperf/hyperf-skeleton (v2.2.1): Extracting archive
Created project in /data/web/test/hyperf-rpc/shop_consumer_user
> @php -r "file_exists('.env') || copy('.env.example', '.env');"
> Installer\Script::install
Setting up optional packages
Setup data and cache dir
Removing installer development dependencies
  What time zone do you want to setup ?
  [n] Default time zone for php.ini
Make your selection or type a time zone name, like Asia/Shanghai (n):
Asia/Shanghai
  Do you want to use Database (MySQL Client) ?
  [y] yes
  [n] None of the above
  Make your selection or type a composer package name and version (yes): n
  Do you want to use Redis Client ?
  [y] yes
  [n] None of the above
  Make your selection or type a composer package name and version (yes): n
  Which RPC protocol do you want to use ?
  [1] JSON RPC with Service Governance
  [2] JSON RPC
  [3] gRPC
  [n] None of the above
  Make your selection or type a composer package name and version (n): n
  Which config center do you want to use ?
  [1] Apollo
  [2] Aliyun ACM
  [3] ETCD
  [4] Nacos
  [n] None of the above
  Make your selection or type a composer package name and version (n): n
  Do you want to use hyperf/constants component ?
  [y] yes
  [n] None of the above
  Make your selection (n): n
  Do you want to use hyperf/async-queue component ? (A simple redis queue component)
  [y] yes
  [n] None of the above
  Make your selection or type a composer package name and version (n): n
  Do you want to use hyperf/amqp component ?
  [y] yes
  [n] None of the above
  Make your selection or type a composer package name and version (n): n
  Do you want to use hyperf/model-cache component ?
  [y] yes
  [n] None of the above
  Make your selection or type a composer package name and version (n): n
  Do you want to use hyperf/elasticsearch component ?
  [y] yes
  [n] None of the above
  Make your selection or type a composer package name and version (n): n
  Do you want to use hyperf/tracer component ? (An open tracing protocol component, adapte with Zipkin etc.)
  [y] yes
  [n] None of the above
  Make your selection or type a composer package name and version (n): n

2蛀序、安裝json rpc依賴

cd shop_consumer_user
composer require hyperf/json-rpc

3欢瞪、安裝 JSON RPC 客戶端

shop_consumer_user 不需要對(duì)外提供服務(wù),所以我們只安裝客戶端徐裸,不需要安裝hyperf/rpc-server組件

composer require hyperf/rpc-client

4遣鼓、server配置

server的配置這里用默認(rèn)的就好了却汉,9501端口提供http服務(wù)掩完,不需要改動(dòng)

'servers' => [
    [
        'name' => 'http',
        'type' => Server::SERVER_HTTP,
        'host' => '0.0.0.0',
        'port' => 9501,
        'sock_type' => SWOOLE_SOCK_TCP,
        'callbacks' => [
            Event::ON_REQUEST => [Hyperf\HttpServer\Server::class, 'onRequest'],
        ],
    ],
],

5龙填、編寫(xiě)業(yè)務(wù)代碼

5-1菊匿、編寫(xiě)服務(wù)消費(fèi)者類(lèi)

app下新建JsonRpc目錄咙咽,編寫(xiě)UserService.php和UserServiceInterface.php文件

【UserServiceInterface.php】

<?php
namespace App\JsonRpc;
interface UserServiceInterface
{
    public function createUser(string $name, int $gender);
    public function getUserInfo(int $id);
}
<span class="redactor-invisible-space">

</span>【UserService.php】

<?php
namespace App\JsonRpc;
use Hyperf\RpcClient\AbstractServiceClient;
class UserService extends AbstractServiceClient implements UserServiceInterface
{
    /**
     * 定義對(duì)應(yīng)服務(wù)提供者的服務(wù)名稱
     * @var string
     */
    protected $serviceName = 'UserService';
    /**
     * 定義對(duì)應(yīng)服務(wù)提供者的服務(wù)協(xié)議
     * @var string
     */
    protected $protocol = 'jsonrpc-http';
    /**
     * @param string $name
     * @param int $gender
     * @return mixed
     */
    public function createUser(string $name, int $gender)
    {
        return $this->__request(__FUNCTION__, compact('name', 'gender'));
    }
    /**
     * @param int $id
     * @return mixed
     */
    public function getUserInfo(int $id)
    {
        return $this->__request(__FUNCTION__, compact('id'));
    }
}

hyperf 官方的hyperf/rpc-client組件已經(jīng)幫我們實(shí)現(xiàn)了rpc遠(yuǎn)程調(diào)用的實(shí)現(xiàn)俏拱,所以我們只需要再配置一下服務(wù)消費(fèi)者勤家,告訴hyperf從哪個(gè)節(jié)點(diǎn)哪個(gè)端口調(diào)用即可抵卫。

5-2健民、consumer配置

config/autoload/services.php內(nèi)定義consumers如下:(沒(méi)有services.php文件的可以自行創(chuàng)建)

<?php
return [
    'consumers' => [
        [
            // 對(duì)應(yīng)消費(fèi)者類(lèi)的 $serviceName
            'name' => 'UserService',
            // 直接對(duì)指定的節(jié)點(diǎn)進(jìn)行消費(fèi)抒巢,通過(guò)下面的 nodes 參數(shù)來(lái)配置服務(wù)提供者的節(jié)點(diǎn)信息
            'nodes' => [
                ['host' => '127.0.0.1', 'port' => 9600],
            ],
        ]
    ],
];

5-3、配置 UserServiceInterface

為了可以方便的注入 UserServiceInterface秉犹,我們?cè)?config/autoload/dependencies.php 內(nèi)定義 UserServiceInterface 和 UserService 的關(guān)系如下:

App\JsonRpc\UserServiceInterface::class => App\JsonRpc\UserService::class,

5-4蛉谜、編寫(xiě)UserController,實(shí)現(xiàn)獲取用戶和創(chuàng)建用戶的接口調(diào)用

【app\Controller\UserController.php】

<?php
declare(strict_types=1);
namespace App\Controller;
use App\JsonRpc\UserServiceInterface;
use Hyperf\Di\Annotation\Inject;
use Hyperf\HttpServer\Annotation\AutoController;
/**
 * Class UserController
 * @package App\Controller
 * @AutoController()
 */
class UserController extends AbstractController
{
    /**
     * @Inject()
     * @var UserServiceInterface
     */
    private $userServiceClient;
    public function createUser()
    {
        $name = (string) $this->request->input('name', '');
        $gender = (int) $this->request->input('gender', 0);
        return $this->userServiceClient->createUser($name, $gender);
    }
    public function getUserInfo()
    {
        $id = (int) $this->request->input('id');
        return $this->userServiceClient->getUserInfo($id);
    }
}

6崇堵、postman訪問(wèn)測(cè)試

啟動(dòng)shop_consumer_user項(xiàng)目的同時(shí)型诚,務(wù)必要保證 shop_provider_user 也啟動(dòng)了,不然請(qǐng)求會(huì)失敗鸳劳。

image
image

7狰贯、自動(dòng)配置服務(wù)消費(fèi)者

你可能已經(jīng)注意到 app\JsonRpc\UserService 類(lèi)的方法并沒(méi)有實(shí)際意義,只是構(gòu)建參數(shù)發(fā)起請(qǐng)求并返回響應(yīng)結(jié)果赏廓,千篇一律的操作著實(shí)增加了復(fù)雜度涵紊。hyperf支持自動(dòng)配置服務(wù)消費(fèi)者代理類(lèi)(生產(chǎn)者暫不支持自動(dòng)配置)。

自動(dòng)配置非常簡(jiǎn)單幔摸,只需要在 consumer 配置項(xiàng)增加service配置即可摸柄,如下:

return [
    'consumers' => [
        [
            // 對(duì)應(yīng)消費(fèi)者類(lèi)的 $serviceName
            'name' => 'UserService',
            // 服務(wù)接口名,可選既忆,默認(rèn)值等于 name 配置的值驱负,如果 name 直接定義為接口類(lèi)則可忽略此行配置嗦玖,
            // 如 name 為字符串則需要配置 service 對(duì)應(yīng)到接口類(lèi)
            'service' => \App\JsonRpc\UserServiceInterface::class,
            // 直接對(duì)指定的節(jié)點(diǎn)進(jìn)行消費(fèi),通過(guò)下面的 nodes 參數(shù)來(lái)配置服務(wù)提供者的節(jié)點(diǎn)信息
            'nodes' => [
                ['host' => '127.0.0.1', 'port' => 9600],
            ],
        ]
    ],
];

現(xiàn)在我們做兩件事电媳,測(cè)試consumer走的是自動(dòng)配置還是手動(dòng)創(chuàng)建的UserService

  1. 把 config/autoload/dependencies.php 內(nèi)定義 UserServiceInterface 和 UserService 的關(guān)系屏蔽
  2. 在 App\JsonRpc\UserService::getUserInfo() 方法內(nèi)打印點(diǎn)數(shù)據(jù)測(cè)試
GET請(qǐng)求 http://127.0.0.1:9501/user/getUserInfo?id=2
結(jié)果發(fā)現(xiàn)控制臺(tái)并沒(méi)有任何輸出踏揣,走的是自動(dòng)配置的consumer

反過(guò)來(lái)

  1. 我們?cè)侔?config/autoload/dependencies.php 內(nèi)定義 UserServiceInterface 和 UserService 的關(guān)系放開(kāi)
  2. 把 config/autoload/services.php 文件內(nèi) consumers 的配置項(xiàng) service 屏蔽
GET請(qǐng)求 http://127.0.0.1:9501/user/getUserInfo?id=2
string(36) "App\JsonRpc\UserService::getUserInfo"
發(fā)現(xiàn)控制臺(tái)輸出了我們?cè)?App\JsonRpc\UserService::getUserInfo() 方法內(nèi)打印的數(shù)據(jù)庆亡,
走的是手動(dòng)創(chuàng)建的consumer

在沒(méi)有特殊情況下匾乓,后續(xù)consumer我們僅做配置,不在手動(dòng)創(chuàng)建又谋,因?yàn)闆](méi)有創(chuàng)建的必要拼缝。

8、配置優(yōu)化

我們注意到 config/autoload/services.php 文件內(nèi) consumers 的配置彰亥,一個(gè)服務(wù)是一個(gè)配置咧七,服務(wù)消費(fèi)者需要消費(fèi)的服務(wù)可能很多,所以我們很有必要優(yōu)化下這里的寫(xiě)法任斋,下面是參考官網(wǎng)的寫(xiě)法:

// 服務(wù)定義
$consumerServices = [
    'UserService' => \App\JsonRpc\UserServiceInterface::class,
];
return [
    'consumers' => value(function () use ($consumerServices) {
        $consumers = [];
        foreach ($consumerServices as $name => $interface) {
            $consumers[] = [
                'name' => $name,
                'service' => $interface,
                'nodes' => [
                    ['host' => '127.0.0.1', 'port' => 9600],
                ],
            ];
        }
        return $consumers;
    }),
];

這樣一來(lái)继阻,我們每次只需要在數(shù)組 $consumerServices 內(nèi)添加需要新的服務(wù)即可。

最后废酷,我們來(lái)看一個(gè)比較大的問(wèn)題瘟檩。

consumer拿到的結(jié)果,又是字符串又是對(duì)象澈蟆,還動(dòng)不動(dòng)直接 Internal Server Error. 數(shù)據(jù)格式的不統(tǒng)一非常不利于前端小伙伴解析墨辛。

統(tǒng)一結(jié)果處理

為了規(guī)范,我們制定了一個(gè)簡(jiǎn)單的標(biāo)準(zhǔn)趴俘,統(tǒng)一返回帶有code睹簇,message,data的數(shù)據(jù)格式寥闪,有興趣的小伙伴可以先研究下怎么解決這個(gè)問(wèn)題太惠,我們下一節(jié)繼續(xù)。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末疲憋,一起剝皮案震驚了整個(gè)濱河市凿渊,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌柜某,老刑警劉巖嗽元,帶你破解...
    沈念sama閱讀 211,423評(píng)論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異喂击,居然都是意外死亡剂癌,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,147評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門(mén)翰绊,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)佩谷,“玉大人旁壮,你說(shuō)我怎么就攤上這事⌒程矗” “怎么了抡谐?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,019評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)桐猬。 經(jīng)常有香客問(wèn)我麦撵,道長(zhǎng),這世上最難降的妖魔是什么溃肪? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,443評(píng)論 1 283
  • 正文 為了忘掉前任免胃,我火速辦了婚禮,結(jié)果婚禮上惫撰,老公的妹妹穿的比我還像新娘羔沙。我一直安慰自己,他們只是感情好厨钻,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,535評(píng)論 6 385
  • 文/花漫 我一把揭開(kāi)白布扼雏。 她就那樣靜靜地躺著,像睡著了一般夯膀。 火紅的嫁衣襯著肌膚如雪诗充。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,798評(píng)論 1 290
  • 那天棍郎,我揣著相機(jī)與錄音其障,去河邊找鬼。 笑死涂佃,一個(gè)胖子當(dāng)著我的面吹牛励翼,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播辜荠,決...
    沈念sama閱讀 38,941評(píng)論 3 407
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼汽抚,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了伯病?” 一聲冷哼從身側(cè)響起造烁,我...
    開(kāi)封第一講書(shū)人閱讀 37,704評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎午笛,沒(méi)想到半個(gè)月后惭蟋,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,152評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡药磺,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,494評(píng)論 2 327
  • 正文 我和宋清朗相戀三年告组,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片癌佩。...
    茶點(diǎn)故事閱讀 38,629評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡木缝,死狀恐怖便锨,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情我碟,我是刑警寧澤放案,帶...
    沈念sama閱讀 34,295評(píng)論 4 329
  • 正文 年R本政府宣布,位于F島的核電站矫俺,受9級(jí)特大地震影響吱殉,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜恳守,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,901評(píng)論 3 313
  • 文/蒙蒙 一考婴、第九天 我趴在偏房一處隱蔽的房頂上張望贩虾。 院中可真熱鬧催烘,春花似錦、人聲如沸缎罢。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,742評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)策精。三九已至舰始,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間咽袜,已是汗流浹背丸卷。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,978評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留询刹,地道東北人谜嫉。 一個(gè)月前我還...
    沈念sama閱讀 46,333評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像凹联,于是被迫代替她去往敵國(guó)和親沐兰。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,499評(píng)論 2 348

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