百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 博客教程 > 正文

hyperf笔记 hyper-

connygpt 2024-10-19 04:01 10 浏览

hyperf环境搭建

使用docker配置环境

docker run --name hyperf \
-v ~/pythonschool/hyperf:/data/project \
-p 9501:9501 -it \
--privileged -u root \
--entrypoint /bin/sh \
hyperf/hyperf:7.4-alpine-v3.11-swoole

复制

全选

cd /data
composer config -g repo.packagist composer https://mirrors.aliyun.com/composer
composer create-project hyperf/hyperf-skeleton project

复制

全选

本地安装php-redis

wget http://pecl.php.net/get/redis-5.3.4.tgz
tar xf redis-5.3.4.tgz
cd redis-5.3.4
phpize
./configure
make
sudo make install
php -m | grep redis

复制

全选

vim /etc/php.ini

extension=redis.so

复制

全选

安装hyperf

用composer自动创建项目和执行脚本

composer config repo.packagist composer https://mirrors.aliyun.com/composer/
composer create-project hyperf/hyperf-skeleton

复制

全选

手动处理

echo {}>composer.json
composer config repo.packagist composer https://mirrors.aliyun.com/composer/
composer require hyperf/hyperf-skeleton
cp -R ./vendor/hyperf/hyperf-skeleton/ .
composer config repo.packagist composer https://mirrors.aliyun.com/composer/
composer update
// 一路回车,默认配置安装
cp .env.example .env
git add .
git commit -am "add hyperf"

复制

全选

如果端口被占用则修改端口,/config/autoload/server.php => port => 9502

// localhost:9502
php bin/hyperf.php start

复制

全选

hyperf调试

因为hyperf使用了swoole,使用常驻内存的方法,会导致代码修改好不能立即生效.

在本地调试的时候,可以更改一些配置.

/config/autoload/server.php => OPTION_MAX_REQUEST => 1
'max_request' => 1, // 设置worker进程的最大任务数

复制

全选

这样hyperf执行完一个任务后,会新建一个worker,代码就会被自动加载.

hyperf生命周期

Self-calling自调用函数闭包

当函数被创建的时候就会自动执行

(function($s) {
    echo $s;
})('Hello Moments');

复制

全选

__invoke

当尝试以调用函数的方式调用一个对象时,__invoke()方法会被自动调用.

class Invoke
{
    public function __invoke()
    {
        echo 'Hello Moments';
    }
}
$invoke = new Invoke();
$invoke(); // 没有__invoke方法则会报错

复制

全选

AOP切面编程

通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术.

php bin/hyperf.php 命令来生成所有代理类
然后再更改config/config.php的SCAN_CACHEABLE为true
可以加快启动速度,减少内存消耗

复制

全选

自定义注释功能,注解

composer require doctrine/annotations
AnnotationRegistry::registerLoader('class_exists');

复制

全选

hyperf执行过程

// 加载composer组件包
require BASE_PATH . '/vendor/autoload.php';
// 切面编程代理类路径
$proxyFileDirPath = BASE_PATH . '/runtime/container/proxy/';
// 配置文件路径
$configDir = BASE_PATH . '/config/';
// 返回所有已注册的 __autoload() 函数
$loaders = spl_autoload_functions();
// 注册注解功能
AnnotationRegistry::registerLoader(function ($class) use ($composerClassLoader) {
    return (bool) $composerClassLoader->findFile($class);
});
// 将composer的类加载改成hyperf
$loader[0] = new static($composerClassLoader, $proxyFileDirPath, $configDir);
// .env环境变量加载处理
$this->loadDotenv();
// 处理配置文件,可以使用class_map替换相应的类
// config/autoload/annotations.php => scan => class_map
$config = ScanConfig::instance($configDir);
$classLoader->addClassMap($config->getClassMap());
// 创建容器
$container = require BASE_PATH . '/config/container.php';
// ApplicationFactory进行注册然后返回Symfony\Component\Console\Application
$application = $container->get(Hyperf\Contract\ApplicationInterface::class);
$application->run();

复制

全选

debug模式下,控制台输出的信息

$container->get(Hyperf\Contract\ApplicationInterface::class);
Hyperf\Di\Container::class->make(Hyperf\Contract\ApplicationInterface::class);
Hyperf\Di\Resolver\FactoryResolver::class->resolve();
Hyperf\Framework\ApplicationFactory::class->__invoke($container);
$eventDispatcher->dispatch(new BootApplication());
Hyperf\Event\EventDispatcher::class->dispatch();
$this->dump($listener, $event);
$this->logger->debug(sprintf('Event %s handled by %s listener.', $eventName, $listenerName));

复制

全选

  • 获取StartServer类的配置
// Hyperf\Di\ClassLoader::class->init()
$loader[0] = new static($composerClassLoader, $proxyFileDirPath, $configDir);
// Hyperf\Di\ClassLoader::class->__construct($composerClassLoader, $proxyFileDirPath, $configDir)
// Hyperf\Di\Annotation\ScanConfig
$config = ScanConfig::instance($configDir);
[$config, $serverDependencies, $cacheable] = static::initConfigByFile($configDir);
$configFromProviders = ProviderConfig::load();
// Hyperf\Config\ProviderConfig
static::$providerConfigs = static::loadProviders($providers);
$providerConfigs[] = (new $provider())();
// Hyperf\Server\ConfigProvider
'commands' => [
    StartServer::class,
],

复制

全选

  • 然后执行指定的命令类
$application = $container->get(Hyperf\Contract\ApplicationInterface::class);
return $this->resolvedEntries[$name] = $this->make($name);
// Hyperf\Di\Resolver\FactoryResolver
resolve()
$object = call($callable, [$this->container]);
// Hyperf\Framework\ApplicationFactory
__invoke()
$application = new Application();
// 到这里时已经把本地命令行添加到Symfony\Component\Console中
$application->add($container->get($command));
// bin/hyperf.php start
$application->run();
// Symfony\Component\Console::class->run();
// Symfony\Component\Console\Input\ArgvInput类对参数做了访问控制(私有),所以看不到
// $_SERVER['argv'][1]取出start命令

复制

全选

php bin/hyperf.php

框架初始化

php bin/hyperf.php start

框架初始化后,执行start命令类StartServer

hyperf路由

基本上都延用了laravel的规范,虽然精简了很多,直接用就好.

Router::post('/post', 'App\Controller\IndexController::post');

复制

全选

自定义路由config/autoload/annotations.php

将\Hyperf\HttpServer\Router\DispatcherFactory::class复制到class_map文件夹下即可.

'class_map' => [
    \Hyperf\HttpServer\Router\DispatcherFactory::class => BASE_PATH . '/class_map/Hyperf/HttpServer/Router/DispatcherFactory.php'
]

复制

全选

使用注解定义路由

关闭config/config.php里的参数SCAN_CACHEABLE = false

新建的类更新一下composer以防找不到,composer dump

php bin/hyperf.php gen:controller AnnotateController

复制

全选

use Hyperf\HttpServer\Annotation\AutoController;
/**
 * @AutoController()
 */
class AnnotateController

复制

全选

/**
 * @Controller()
 */
class AnnotateController

/**
 * @RequestMapping(path="index", methods="get,post")
 */
public function index(RequestInterface $request, ResponseInterface $response)

复制

全选

hyperf注意事项

尽量不要用全局变量,因为要自己手动释放.

使用上下文来进行逻辑处理.

使用注解一定要重启服务!

服务调用jsonrpc-http

基础实现

分成两个主体,服务提供者(TestService:9504),服务消费者(TestServiceConsumer:9502).

通过服务契约来定义和约束接口的调用(TestServiceInterface).

服务提供者:TestServiceInterface,TestService,config/autoload/server.php

服务消费者:TestServiceInterface,TestServiceConsumer(自动生成可省),config/autoload/services.php

路由指定节点信息(nodes),路由负载均衡(registry)

服务提供者

composer require hyperf/json-rpc
composer require hyperf/rpc-server
mkdir app/JsonRpc
// TestServiceInterface.php
// TestService.php
// 添加server:9504

复制

全选

@RpcService(name="TestService",protocol="jsonrpc-http",server="jsonrpc-http")

复制

全选

服务消费者

composer require hyperf/json-rpc
composer require hyperf/rpc-client
services.php->consumers->service(自动生成要指定接口)

复制

全选

服务网关

// http://localhost:9502/rpc

Router::get('/rpc', function(){
    $client = \Hyperf\Utils\ApplicationContext::getContainer()->get(\App\JsonRpc\TestServiceInterface::class);
    $result = $client->sum(11,22);
    return 'rpc' . $result;
});

复制

全选

手动生成服务消费者

// TestServiceConsumer
// dependencies.php注入一下对象

复制

全选

config/autoload/services.php

'consumers' => [
    [
        'name' => 'TestService',
        'nodes' => [
            ['host' => '127.0.0.1', 'port' => 9504]
        ]
    ]
]

复制

全选

路由负载均衡

服务提供者(publishTo)->服务注册(consul)

服务消费者(registry)->负载均衡(consul)

服务调用grpc

需要安装如下软件.

  • php-grpc扩展
  • php-protobuf扩展
  • protoc命令行工具
  • grpc_php_plugin模板生成工具
  • swoole开启openssl,http2

protoc生成规范

根目录下新建模板文件,grpc.proto

vim grpc.proto

syntax = "proto3";
package grpc;
service Hi {
    rpc sayHello (HiUser) returns (HiReply) {}
}
message HiUser {
    string name = 1;
}
message HiReply {
    string message = 1;
}

复制

全选

// 根目录添加目录,并加入命名空间
mkdir grpc
// 只生成接口规范
protoc --php_out=grpc/ grpc.proto
// 生成php类模板
protoc -I=. grpc.proto --proto_path=grpc/ --php_out=grpc/ --grpc_out=grpc/ --plugin=protoc-gen-grpc=../grpc_php_plugin

复制

全选

grpc目录结构

grpc
├── GPBMetadata
│   └── Grpc.php
└── Grpc
    ├── HiClient.php // 由grpc_php_plugin生成
    ├── HiReply.php
    └── HiUser.php

复制

全选

添加命名空间

"autoload": {
    "psr-4": {
        "App\\": "app/",
        "GPBMetadata\\": "grpc/GPBMetadata",
        "Grpc\\": "grpc/Grpc"
    },

复制

全选

修改grpc/Grpc/HiClient.php的基类为Hyperf\GrpcClient\BaseClient;

class HiClient extends \Grpc\BaseStub
==> 
class HiClient extends BaseClient

复制

全选

服务提供者

composer require hyperf/grpc-server

复制

全选

添加服务器配置:9505

[
    'name' => 'grpc',
    'type' => Server::SERVER_HTTP,
    'host' => '0.0.0.0',
    'port' => 9505,
    'sock_type' => SWOOLE_SOCK_TCP,
    'callbacks' => [
        Event::ON_REQUEST => [Hyperf\GrpcServer\Server::class, 'onRequest'],
    ],
]

复制

全选

配置控制器

php bin/hyperf.php gen:controller HiController

复制

全选

app/Controller/HiController.php

use Grpc\HiReply;
use Grpc\HiUser;
class HiController
{
    public function sayHello(HiUser $user)
    {
        $message = new HiReply();
        $message->setMessage(sprintf('Hello %s(%s)', $user->getName(), time()));
        return $message;
    }
}

复制

全选

配置路由,要注意大小写,以protoc生成的接口文档为准.

在HiClient中,如'/grpc.Hi/sayHello'.

Router::addServer('grpc', function () {
    Router::addGroup('/grpc.Hi', function () {
        Router::post('/sayHello', [App\Controller\HiController::class, 'sayHello']);
    });
});

复制

全选

服务消费者

composer require hyperf/grpc-client

复制

全选

直接在路由里测试,

Router::get('/grpc', function () {
    $client = new \Grpc\HiClient('127.0.0.1:9505', ['credentials' => null]);

    $request = new \Grpc\HiUser();
    $request->setName('hyperf');

    /**
     * @var \Grpc\HiReply $reply
     */
    list($reply, $state) = $client->sayHello($request);

    return $reply->getMessage();
});

复制

全选

测试

php bin/hyperf.php s

http://localhost:9502/grpc

服务中心

必须要先了解微服务再去看hyperf框架,毕竟是国内开源的可以参考了解一下,辅助学习,看一下此框架如何整合微服务的组件.

不要光看文档,文档不会面面俱到,先看原理,多搜索,借用框架实际操作一下.

安装服务中心

https://learn.hashicorp.com/

brew tap hashicorp/tap
brew install hashicorp/tap/consul
consul -v

复制

全选

运行服务中心

consul agent -http-port=8500 -dev
http://localhost:8500/

复制

全选

配置服务中心

composer require hyperf/service-governance
composer require hyperf/consul
composer require hyperf/guzzle

复制

全选

config/autoload/consul.php

php bin/hyperf.php vendor:publish hyperf/consul

return [
    'uri' => 'http://127.0.0.1:8500',
];

复制

全选

发布服务到服务中心publishTo="consul"

/**
 * @RpcService(name="TestService",protocol="jsonrpc-http",server="jsonrpc-http",publishTo="consul")
 */
class TestService implements TestServiceInterface

复制

全选

config/autoload/services.php

'registry' => [
    'protocol' => 'consul',
    'address' => 'http://127.0.0.1:8500',
],

复制

全选

测试地址 http://127.0.0.1:9502/consul

consul键值对存储

Router::get('/consul', function(){
    $container = \Hyperf\Utils\ApplicationContext::getContainer();
    $clientFactory = $container->get(\Hyperf\Guzzle\ClientFactory::class);
    $consulServer = 'http://127.0.0.1:8500';
    // consul键值对存储
    $kv = new \Hyperf\Consul\KV(function () use ($clientFactory, $consulServer) {
        return $clientFactory->create([
            'base_uri' => $consulServer,
        ]);
    });
    $kv->put('consul', 'Hello World!');
    $result = $kv->get('consul')->getBody()->read(1024);
    $kv->delete('consul');
    var_dump(base64_decode(json_decode($result)[0]->Value));

    return 'consule ' . $result;
});

复制

全选

代理操作

$agent = new \Hyperf\Consul\Agent(function () use ($clientFactory, $consulServer) {
    return $clientFactory->create([
        'base_uri' => $consulServer,
    ]);
});
var_dump($agent->services()->getBody()->read(1024));
return $agent->services()->getBody();

复制

全选

{
    "TestService-0": {
        "ID": "TestService-0",
        "Service": "TestService",
        "Tags": [],
        "Meta": {
            "Protocol": "jsonrpc-http"
        },
        "Port": 9504,
        "Address": "192.168.1.5",
        "SocketPath": "",
        "TaggedAddresses": {
            "lan_ipv4": {
                "Address": "192.168.1.5",
                "Port": 9504
            },
            "wan_ipv4": {
                "Address": "192.168.1.5",
                "Port": 9504
            }
        },
        "Weights": {
            "Passing": 1,
            "Warning": 1
        },
        "EnableTagOverride": false,
        "Datacenter": "dc1"
    }
}

相关推荐

3分钟让你的项目支持AI问答模块,完全开源!

hello,大家好,我是徐小夕。之前和大家分享了很多可视化,零代码和前端工程化的最佳实践,今天继续分享一下最近开源的Next-Admin的最新更新。最近对这个项目做了一些优化,并集成了大家比较关注...

干货|程序员的副业挂,12个平台分享

1、D2adminD2Admin是一个完全开源免费的企业中后台产品前端集成方案,使用最新的前端技术栈,小于60kb的本地首屏js加载,已经做好大部分项目前期准备工作,并且带有大量示例代码,助...

Github标星超200K,这10个可视化面板你知道几个

在Github上有很多开源免费的后台控制面板可以选择,但是哪些才是最好、最受欢迎的可视化控制面板呢?今天就和大家推荐Github上10个好看又流行的可视化面板:1.AdminLTEAdminLTE是...

开箱即用的炫酷中后台前端开源框架第二篇

#头条创作挑战赛#1、SoybeanAdmin(1)介绍:SoybeanAdmin是一个基于Vue3、Vite3、TypeScript、NaiveUI、Pinia和UnoCSS的清新优...

搭建React+AntDeign的开发环境和框架

搭建React+AntDeign的开发环境和框架随着前端技术的不断发展,React和AntDesign已经成为越来越多Web应用程序的首选开发框架。React是一个用于构建用户界面的JavaScrip...

基于.NET 5实现的开源通用权限管理平台

??大家好,我是为广大程序员兄弟操碎了心的小编,每天推荐一个小工具/源码,装满你的收藏夹,每天分享一个小技巧,让你轻松节省开发效率,实现不加班不熬夜不掉头发,是我的目标!??今天小编推荐一款基于.NE...

StreamPark - 大数据流计算引擎

使用Docker完成StreamPark的部署??1.基于h2和docker-compose进行StreamPark部署wgethttps://raw.githubusercontent.com/a...

教你使用UmiJS框架开发React

1、什么是Umi.js?umi,中文可发音为乌米,是一个可插拔的企业级react应用框架。你可以将它简单地理解为一个专注性能的类next.js前端框架,并通过约定、自动生成和解析代码等方式来辅助...

简单在线流程图工具在用例设计中的运用

敏捷模式下,测试团队的用例逐渐简化以适应快速的发版节奏,大家很早就开始运用思维导图工具比如xmind来编写测试方法、测试点。如今不少已经不少利用开源的思维导图组件(如百度脑图...)来构建测试测试...

【开源分享】神奇的大数据实时平台框架,让Flink&Spark开发更简单

这是一个神奇的框架,让Flink|Spark开发更简单,一站式大数据实时平台!他就是StreamX!什么是StreamX大数据技术如今发展的如火如荼,已经呈现百花齐放欣欣向荣的景象,实时处理流域...

聊聊规则引擎的调研及实现全过程

摘要本期主要以规则引擎业务实现为例,陈述在陌生业务前如何进行业务深入、调研、技术选型、设计及实现全过程分析,如果你对规则引擎不感冒、也可以从中了解一些抽象实现过程。诉求从硬件采集到的数据提供的形式多种...

【开源推荐】Diboot 2.0.5 发布,自动化开发助理

一、前言Diboot2.0.5版本已于近日发布,在此次发布中,我们新增了file-starter组件,完善了iam-starter组件,对core核心进行了相关优化,让devtools也支持对IAM...

微软推出Copilot Actions,使用人工智能自动执行重复性任务

IT之家11月19日消息,微软在今天举办的Ignite大会上宣布了一系列新功能,旨在进一步提升Microsoft365Copilot的智能化水平。其中最引人注目的是Copilot...

Electron 使用Selenium和WebDriver

本节我们来学习如何在Electron下使用Selenium和WebDriver。SeleniumSelenium是ThoughtWorks提供的一个强大的基于浏览器的开源自动化测试工具...

Quick 'n Easy Web Builder 11.1.0设计和构建功能齐全的网页的工具

一个实用而有效的应用程序,能够让您轻松构建、创建和设计个人的HTML网站。Quick'nEasyWebBuilder是一款全面且轻巧的软件,为用户提供了一种简单的方式来创建、编辑...