更新
This commit is contained in:
parent
e84acb95b9
commit
3500b5eec0
@ -12,7 +12,7 @@ export default [
|
||||
{ text: '初始化依赖注入 (DI) 容器', link: hyperf + 'DI' },
|
||||
{ text: '初始化容器类', link: hyperf + 'container' },
|
||||
{ text: '启动服务', link: hyperf + '启动服务' },
|
||||
{ text: '请求', link: hyperf + '请求' },
|
||||
{ text: '接收请求', link: hyperf + '接收请求' },
|
||||
{ text: '路由寻址', link: hyperf + '路由寻址' },
|
||||
{ text: '中间件', link: hyperf + '中间件' },
|
||||
{ text: '响应', link: hyperf + '响应' },
|
||||
@ -20,6 +20,7 @@ export default [
|
||||
{ text: '附录2 注解命令获取', link: hyperf + '附录2 注解命令获取' },
|
||||
{ text: '附录3 命令注册Application', link: hyperf + '附录3 命令注册Application' },
|
||||
{ text: '附录4 Application Run方法', link: hyperf + '附录4 Application_Run' },
|
||||
{ text: '附录5 初始化中间件', link: hyperf + '附录5 初始化中间件' },
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -527,6 +527,7 @@ class ServerFactory
|
||||
::: details 点我查看`ServerConfig`
|
||||
|
||||
::: code-group
|
||||
|
||||
```php [ServerConfig]
|
||||
namespace Hyperf\Server;
|
||||
|
||||
@ -630,6 +631,7 @@ class ServerConfig implements Arrayable
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```php [Server build]
|
||||
namespace Hyperf\Server;
|
||||
|
||||
@ -771,6 +773,7 @@ class Port
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
:::
|
||||
2. 根据`Server`配置的服务类型,实例化对应服务,调用服务的`init`方法
|
||||
::: tip
|
||||
@ -786,9 +789,11 @@ class Port
|
||||
// $this->getServer()返回的是一个Hyperf/Server/Server类实例
|
||||
$this->getServer()->init($this->config);
|
||||
```
|
||||
|
||||
> 文件位置:/vendor/hyperf/server/src/Server.php
|
||||
|
||||
::: code-group
|
||||
|
||||
```php [init方法]
|
||||
public function init(ServerConfig $config): ServerInterface
|
||||
{
|
||||
@ -797,6 +802,7 @@ public function init(ServerConfig $config): ServerInterface
|
||||
return $this;
|
||||
}
|
||||
```
|
||||
|
||||
```php [initServers方法]
|
||||
protected function initServers(ServerConfig $config)
|
||||
{
|
||||
@ -848,6 +854,7 @@ protected function initServers(ServerConfig $config)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```php [sortServer方法]
|
||||
protected function sortServers(array $servers): array
|
||||
{
|
||||
@ -875,6 +882,7 @@ protected function sortServers(array $servers): array
|
||||
return $sortServers;
|
||||
}
|
||||
```
|
||||
|
||||
```php [Server类源码]
|
||||
namespace Hyperf\Server;
|
||||
|
||||
@ -1072,85 +1080,286 @@ class Server implements ServerInterface
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
:::
|
||||
分析`sortServicers`方法,
|
||||
分析`sortServicers`方法, 对`Server`进行排序,确保 `HTTP` 服务器和 `WebSocket` 服务器按特定顺序排列
|
||||
|
||||
```php
|
||||
// $config->getServers()返回的是一个Hyperf\Server\Port类对象数组
|
||||
$servers = $this->sortServers($config->getServers());
|
||||
```
|
||||
|
||||
这里返回排好序的`Port`类对象数组。
|
||||
|
||||
之后循环遍历`$servers`数组,每个`value`是一个`Port`对象,走`if`
|
||||
::: code-group
|
||||
|
||||
```php
|
||||
foreach ($servers as $server) {
|
||||
$name = $server->getName();
|
||||
$type = $server->getType();
|
||||
$host = $server->getHost();
|
||||
$port = $server->getPort();
|
||||
$sockType = $server->getSockType();
|
||||
$callbacks = $server->getCallbacks();
|
||||
```php [启动Server]
|
||||
foreach ($servers as $server) { // [!code focus]
|
||||
// 获取服务名
|
||||
$name = $server->getName();
|
||||
// 获取服务类型(http or websocket)
|
||||
$type = $server->getType();
|
||||
// 获取绑定的主机地址
|
||||
$host = $server->getHost();
|
||||
// 获取端口
|
||||
$port = $server->getPort();
|
||||
// 获取套接字类型
|
||||
$sockType = $server->getSockType();
|
||||
// 获取回调信息
|
||||
$callbacks = $server->getCallbacks();
|
||||
|
||||
if (! $this->server instanceof SwooleServer) {
|
||||
// 分析makeServer方法
|
||||
// 这里返回的是一个Swoole\Server对象
|
||||
$this->server = $this->makeServer($type, $host, $port, $config->getMode(), $sockType);
|
||||
// 获取所有回调事件,进行合并
|
||||
$callbacks = array_replace($this->defaultCallbacks(), $config->getCallbacks(), $callbacks);
|
||||
// 注册回调事件
|
||||
$this->registerSwooleEvents($this->server, $callbacks, $name);
|
||||
// 设置运行参数
|
||||
$this->server->set(array_replace($config->getSettings(), $server->getSettings()));
|
||||
// 将服务以键值对的形式添加到ServerManager中
|
||||
ServerManager::add($name, [$type, current($this->server->ports)]);
|
||||
// 如果类存在,则触发BeforeMainServerStart事件
|
||||
if (class_exists(BeforeMainServerStart::class)) {
|
||||
// Trigger BeforeMainServerStart event, this event only trigger once before main server start.
|
||||
$this->eventDispatcher->dispatch(new BeforeMainServerStart($this->server, $config->toArray()));
|
||||
}
|
||||
} else {
|
||||
/** @var bool|\Swoole\Server\Port $slaveServer */
|
||||
// $slaveServer = $this->server->addlistener($host, $port, $sockType);
|
||||
// if (! $slaveServer) {
|
||||
// throw new \RuntimeException("Failed to listen server port [{$host}:{$port}]");
|
||||
// }
|
||||
// $server->getSettings() && $slaveServer->set(array_replace($config->getSettings(), $server->getSettings()));
|
||||
// $this->registerSwooleEvents($slaveServer, $callbacks, $name);
|
||||
// ServerManager::add($name, [$type, $slaveServer]);
|
||||
}
|
||||
if (! $this->server instanceof SwooleServer) { // [!code focus:39]
|
||||
// 分析makeServer方法
|
||||
// 这里返回的是一个Swoole\Server对象
|
||||
$this->server = $this->makeServer($type, $host, $port, $config->getMode(), $sockType);
|
||||
// 获取所有回调事件,进行合并
|
||||
$callbacks = array_replace($this->defaultCallbacks(), $config->getCallbacks(), $callbacks);
|
||||
// 注册回调事件
|
||||
$this->registerSwooleEvents($this->server, $callbacks, $name);
|
||||
// 设置运行参数
|
||||
$this->server->set(array_replace($config->getSettings(), $server->getSettings()));
|
||||
// 将服务以键值对的形式添加到ServerManager中
|
||||
ServerManager::add($name, [$type, current($this->server->ports)]);
|
||||
// 如果类存在,则触发BeforeMainServerStart事件
|
||||
if (class_exists(BeforeMainServerStart::class)) {
|
||||
// Trigger BeforeMainServerStart event, this event only trigger once before main server start.
|
||||
$this->eventDispatcher->dispatch(new BeforeMainServerStart($this->server, $config->toArray()));
|
||||
}
|
||||
} else {
|
||||
/** @var bool|\Swoole\Server\Port $slaveServer */
|
||||
$slaveServer = $this->server->addlistener($host, $port, $sockType);
|
||||
if (! $slaveServer) {
|
||||
throw new \RuntimeException("Failed to listen server port [{$host}:{$port}]");
|
||||
}
|
||||
$server->getSettings() && $slaveServer->set(array_replace($config->getSettings(), $server->getSettings()));
|
||||
$this->registerSwooleEvents($slaveServer, $callbacks, $name);
|
||||
ServerManager::add($name, [$type, $slaveServer]);
|
||||
}
|
||||
|
||||
// Trigger beforeStart event.
|
||||
if (isset($callbacks[Event::ON_BEFORE_START])) {
|
||||
[$class, $method] = $callbacks[Event::ON_BEFORE_START];
|
||||
if ($this->container->has($class)) {
|
||||
$this->container->get($class)->{$method}();
|
||||
}
|
||||
}
|
||||
// 如果设置了ON_BEFORE_START回调,则运行该回调
|
||||
if (isset($callbacks[Event::ON_BEFORE_START])) {
|
||||
[$class, $method] = $callbacks[Event::ON_BEFORE_START];
|
||||
if ($this->container->has($class)) {
|
||||
$this->container->get($class)->{$method}();
|
||||
}
|
||||
}
|
||||
if (class_exists(BeforeServerStart::class)) {
|
||||
// 触发BeforeServerStart事件
|
||||
$this->eventDispatcher->dispatch(new BeforeServerStart($name));
|
||||
}
|
||||
} // [!code focus]
|
||||
```
|
||||
|
||||
if (class_exists(BeforeServerStart::class)) {
|
||||
// Trigger BeforeServerStart event.
|
||||
$this->eventDispatcher->dispatch(new BeforeServerStart($name));
|
||||
}
|
||||
```php [Port类]
|
||||
namespace Hyperf\Server;
|
||||
|
||||
class Port
|
||||
{
|
||||
protected string $name = 'http';
|
||||
|
||||
protected int $type = ServerInterface::SERVER_HTTP;
|
||||
|
||||
protected string $host = '0.0.0.0';
|
||||
|
||||
protected int $port = 9501;
|
||||
|
||||
protected int $sockType = 0;
|
||||
|
||||
protected array $callbacks = [];
|
||||
|
||||
protected array $settings = [];
|
||||
|
||||
protected ?Option $options = null;
|
||||
|
||||
public static function build(array $config): static
|
||||
{
|
||||
$config = self::filter($config);
|
||||
|
||||
$port = new static();
|
||||
isset($config['name']) && $port->setName($config['name']);
|
||||
isset($config['type']) && $port->setType($config['type']);
|
||||
isset($config['host']) && $port->setHost($config['host']);
|
||||
isset($config['port']) && $port->setPort($config['port']);
|
||||
isset($config['sock_type']) && $port->setSockType($config['sock_type']);
|
||||
isset($config['callbacks']) && $port->setCallbacks($config['callbacks']);
|
||||
isset($config['settings']) && $port->setSettings($config['settings']);
|
||||
isset($config['options']) && $port->setOptions(Option::make($config['options']));
|
||||
|
||||
return $port;
|
||||
}
|
||||
|
||||
public function getName(): string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
public function setName(string $name): static
|
||||
{
|
||||
$this->name = $name;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getType(): int
|
||||
{
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
public function setType(int $type): static
|
||||
{
|
||||
$this->type = $type;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getHost(): string
|
||||
{
|
||||
return $this->host;
|
||||
}
|
||||
|
||||
public function setHost(string $host): static
|
||||
{
|
||||
$this->host = $host;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getPort(): int
|
||||
{
|
||||
return $this->port;
|
||||
}
|
||||
|
||||
public function setPort(int $port): static
|
||||
{
|
||||
$this->port = $port;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getSockType(): int
|
||||
{
|
||||
return $this->sockType;
|
||||
}
|
||||
|
||||
public function setSockType(int $sockType): static
|
||||
{
|
||||
$this->sockType = $sockType;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getCallbacks(): array
|
||||
{
|
||||
return $this->callbacks;
|
||||
}
|
||||
|
||||
public function setCallbacks(array $callbacks): static
|
||||
{
|
||||
$this->callbacks = $callbacks;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getSettings(): array
|
||||
{
|
||||
return $this->settings;
|
||||
}
|
||||
|
||||
public function setSettings(array $settings): static
|
||||
{
|
||||
$this->settings = $settings;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getOptions(): ?Option
|
||||
{
|
||||
return $this->options;
|
||||
}
|
||||
|
||||
public function setOptions(Option $options): static
|
||||
{
|
||||
$this->options = $options;
|
||||
return $this;
|
||||
}
|
||||
|
||||
private static function filter(array $config): array
|
||||
{
|
||||
if ((int) $config['type'] === ServerInterface::SERVER_BASE) {
|
||||
$default = [
|
||||
'open_http2_protocol' => false,
|
||||
'open_http_protocol' => false,
|
||||
];
|
||||
|
||||
$config['settings'] = array_merge($default, $config['settings'] ?? []);
|
||||
}
|
||||
|
||||
return $config;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
###### makeServer方法
|
||||
```php [config/server配置文件]
|
||||
return [
|
||||
'mode' => SWOOLE_PROCESS,
|
||||
'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'],
|
||||
],
|
||||
'options' => [
|
||||
// Whether to enable request lifecycle event
|
||||
'enable_request_lifecycle' => false,
|
||||
],
|
||||
],
|
||||
],
|
||||
'settings' => [
|
||||
Constant::OPTION_ENABLE_COROUTINE => true,
|
||||
Constant::OPTION_WORKER_NUM => swoole_cpu_num(),
|
||||
Constant::OPTION_PID_FILE => BASE_PATH . '/runtime/hyperf.pid',
|
||||
Constant::OPTION_OPEN_TCP_NODELAY => true,
|
||||
Constant::OPTION_MAX_COROUTINE => 100000,
|
||||
Constant::OPTION_OPEN_HTTP2_PROTOCOL => true,
|
||||
Constant::OPTION_MAX_REQUEST => 100000,
|
||||
Constant::OPTION_SOCKET_BUFFER_SIZE => 2 * 1024 * 1024,
|
||||
Constant::OPTION_BUFFER_OUTPUT_SIZE => 2 * 1024 * 1024,
|
||||
// 将 public 替换为上传目录
|
||||
'document_root' => BASE_PATH . '/public',
|
||||
'enable_static_handler' => true,
|
||||
],
|
||||
'callbacks' => [
|
||||
Event::ON_WORKER_START => [Hyperf\Framework\Bootstrap\WorkerStartCallback::class, 'onWorkerStart'],
|
||||
Event::ON_PIPE_MESSAGE => [Hyperf\Framework\Bootstrap\PipeMessageCallback::class, 'onPipeMessage'],
|
||||
Event::ON_WORKER_EXIT => [Hyperf\Framework\Bootstrap\WorkerExitCallback::class, 'onWorkerExit'],
|
||||
],
|
||||
];
|
||||
```
|
||||
|
||||
分析可知,`makeServer`方法的作用就是根据`$type`参数,返回对应的`Server`类型。
|
||||
根据配置文件中的`type`参数可知,返回的是一个`Swoole\Server`对象实例。
|
||||
:::
|
||||
|
||||
```php
|
||||
##### initServers
|
||||
|
||||
分析可知,`makeServer`方法的作用就是根据`$type`参数,默认返回对应的`Server`类型。
|
||||
根据配置文件中的`type`参数可知,返回的是一个`Swoole\Http\Server`对象实例。
|
||||
::: code-group
|
||||
|
||||
```php [makeServer]
|
||||
$this->server = $this->makeServer($type, $host, $port, $config->getMode(), $sockType);
|
||||
```
|
||||
|
||||
```php [具体实现]
|
||||
use Swoole\Http\Server as SwooleHttpServer;
|
||||
use Swoole\Server as SwooleServer;
|
||||
use Swoole\WebSocket\Server as SwooleWebSocketServer;
|
||||
|
||||
protected function makeServer(int $type, string $host, int $port, int $mode, int $sockType): SwooleServer
|
||||
{
|
||||
switch ($type) {
|
||||
// HTTP类型 (默认)
|
||||
case ServerInterface::SERVER_HTTP:
|
||||
return new SwooleHttpServer($host, $port, $mode, $sockType);
|
||||
// WebSocket类型 (默认)
|
||||
case ServerInterface::SERVER_WEBSOCKET:
|
||||
return new SwooleWebSocketServer($host, $port, $mode, $sockType);
|
||||
// 基础服务TCP类型
|
||||
case ServerInterface::SERVER_BASE:
|
||||
return new SwooleServer($host, $port, $mode, $sockType);
|
||||
}
|
||||
@ -1159,146 +1368,267 @@ protected function makeServer(int $type, string $host, int $port, int $mode, int
|
||||
}
|
||||
```
|
||||
|
||||
###### registerSwooleEvents方法
|
||||
:::
|
||||
|
||||
看这一行,
|
||||
接下来将回调合并, 合并顺序: 默认回调 -> 配置回调 -> 传递的回调, `server`数组中的配置最大,可以覆盖`Server`、默认回调的配置。
|
||||
::: code-group
|
||||
|
||||
```php
|
||||
$callbacks = array_replace($this->defaultCallbacks(), $config->getCallbacks(), $callbacks);
|
||||
```
|
||||
|
||||
```php [具体实现]
|
||||
protected function defaultCallbacks()
|
||||
{
|
||||
$hasCallback = class_exists(Bootstrap\StartCallback::class)
|
||||
&& class_exists(Bootstrap\ManagerStartCallback::class)
|
||||
&& class_exists(Bootstrap\WorkerStartCallback::class);
|
||||
|
||||
if ($hasCallback) {
|
||||
$callbacks = [
|
||||
Event::ON_MANAGER_START => [Bootstrap\ManagerStartCallback::class, 'onManagerStart'],
|
||||
Event::ON_WORKER_START => [Bootstrap\WorkerStartCallback::class, 'onWorkerStart'],
|
||||
Event::ON_WORKER_STOP => [Bootstrap\WorkerStopCallback::class, 'onWorkerStop'],
|
||||
Event::ON_WORKER_EXIT => [Bootstrap\WorkerExitCallback::class, 'onWorkerExit'],
|
||||
];
|
||||
if ($this->server->mode === SWOOLE_BASE) {
|
||||
return $callbacks;
|
||||
}
|
||||
|
||||
return array_merge([
|
||||
Event::ON_START => [Bootstrap\StartCallback::class, 'onStart'],
|
||||
], $callbacks);
|
||||
}
|
||||
|
||||
return [
|
||||
Event::ON_WORKER_START => function (SwooleServer $server, int $workerId) {
|
||||
printf('Worker %d started.' . PHP_EOL, $workerId);
|
||||
},
|
||||
];
|
||||
}
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
根据服务名注册回调,
|
||||
::: details 默认回调列表
|
||||
|
||||
```php
|
||||
Array
|
||||
(
|
||||
[start] => Array
|
||||
(
|
||||
[0] => Hyperf\Framework\Bootstrap\StartCallback
|
||||
[1] => onStart
|
||||
)
|
||||
|
||||
[managerStart] => Array
|
||||
(
|
||||
[0] => Hyperf\Framework\Bootstrap\ManagerStartCallback
|
||||
[1] => onManagerStart
|
||||
)
|
||||
|
||||
[workerStart] => Array
|
||||
(
|
||||
[0] => Hyperf\Framework\Bootstrap\WorkerStartCallback
|
||||
[1] => onWorkerStart
|
||||
)
|
||||
|
||||
[workerStop] => Array
|
||||
(
|
||||
[0] => Hyperf\Framework\Bootstrap\WorkerStopCallback
|
||||
[1] => onWorkerStop
|
||||
)
|
||||
|
||||
[workerExit] => Array
|
||||
(
|
||||
[0] => Hyperf\Framework\Bootstrap\WorkerExitCallback
|
||||
[1] => onWorkerExit
|
||||
)
|
||||
|
||||
[pipeMessage] => Array
|
||||
(
|
||||
[0] => Hyperf\Framework\Bootstrap\PipeMessageCallback
|
||||
[1] => onPipeMessage
|
||||
)
|
||||
|
||||
[request] => Array
|
||||
(
|
||||
[0] => Hyperf\HttpServer\Server
|
||||
[1] => onRequest
|
||||
)
|
||||
|
||||
)
|
||||
```
|
||||
|
||||
:::
|
||||
::: code-group
|
||||
|
||||
```php
|
||||
$this->registerSwooleEvents($this->server, $callbacks, $name);
|
||||
```
|
||||
|
||||
```php [具体实现]
|
||||
protected function registerSwooleEvents(SwoolePort|SwooleServer $server, array $events, string $serverName): void
|
||||
{
|
||||
foreach ($events as $event => $callback) {
|
||||
// beforeStart不是swoole回调事件,会跳过
|
||||
if (! Event::isSwooleEvent($event)) {
|
||||
continue;
|
||||
}
|
||||
if (is_array($callback)) {
|
||||
// 解构出类名和方法名
|
||||
[$className, $method] = $callback;
|
||||
// 如果类名+方法名已经存在,追加到控制台输出警告信息
|
||||
if (array_key_exists($className . $method, $this->onRequestCallbacks)) {
|
||||
$this->logger->warning(sprintf('%s will be replaced by %s. Each server should have its own onRequest callback. Please check your configs.', $this->onRequestCallbacks[$className . $method], $serverName));
|
||||
}
|
||||
// 追加到onRequestCallbacks数组中
|
||||
$this->onRequestCallbacks[$className . $method] = $serverName;
|
||||
// 从容器中解析出回调事件对象实例
|
||||
$class = $this->container->get($className);
|
||||
if (method_exists($class, 'setServerName')) {
|
||||
// Override the server name.
|
||||
$class->setServerName($serverName);
|
||||
}
|
||||
// 最后一个回调事件中,Hyperf\HttpServer\Server是MiddlewareInitializerInterface的实现类
|
||||
// 所以会进入该if
|
||||
// 这里会初始化中间件
|
||||
if ($class instanceof MiddlewareInitializerInterface) {
|
||||
$class->initCoreMiddleware($serverName);
|
||||
}
|
||||
$callback = [$class, $method];
|
||||
}
|
||||
// 在server上注册回调事件
|
||||
$server->on($event, $callback);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
这是所有的回调事件,如下图
|
||||
![](https://oss.xiaokeaii.top/2024/event.png)
|
||||
|
||||
查看以下代码,这里进行配置和初始化中间件相关的内容
|
||||
|
||||
```php
|
||||
$class->initCoreMiddleware($serverName);
|
||||
```
|
||||
|
||||
> 文件位置:/vendor/hyperf/http-server/src/Server.php
|
||||
|
||||
```php
|
||||
public function initCoreMiddleware(string $serverName): void
|
||||
{
|
||||
// http
|
||||
$this->serverName = $serverName;
|
||||
// 创建核心中间件对象实例
|
||||
$this->coreMiddleware = $this->createCoreMiddleware();
|
||||
|
||||
$config = $this->container->get(ConfigInterface::class);
|
||||
// 获取配置的中间件
|
||||
$this->middlewares = $config->get('middlewares.' . $serverName, []);
|
||||
// 设置异常处理器
|
||||
$this->exceptionHandlers = $config->get('exceptions.handler.' . $serverName, $this->getDefaultExceptionHandler());
|
||||
// 设置服务的option选项,对中间件进行排序
|
||||
$this->initOption();
|
||||
}
|
||||
```
|
||||
|
||||
逐行分析,
|
||||
|
||||
```php
|
||||
protected function createCoreMiddleware(): CoreMiddlewareInterface
|
||||
{
|
||||
return make(CoreMiddleware::class, [$this->container, $this->serverName]);
|
||||
}
|
||||
// make方法从容器中获取对象实例
|
||||
function make(string $name, array $parameters = [])
|
||||
{
|
||||
if (ApplicationContext::hasContainer()) {
|
||||
/** @var \Hyperf\Di\Container $container */
|
||||
$container = ApplicationContext::getContainer();
|
||||
if (method_exists($container, 'make')) {
|
||||
return $container->make($name, $parameters);
|
||||
foreach ($events as $event => $callback) {
|
||||
if (! Event::isSwooleEvent($event)) {
|
||||
continue;
|
||||
}
|
||||
if (is_array($callback)) {
|
||||
// 获取事件对应class和回调方法
|
||||
[$className, $method] = $callback;
|
||||
if (array_key_exists($className . $method, $this->onRequestCallbacks)) {
|
||||
$this->logger->warning(sprintf('%s will be replaced by %s. Each server should have its own onRequest callback. Please check your configs.', $this->onRequestCallbacks[$className . $method], $serverName));
|
||||
}
|
||||
// 记录回调
|
||||
$this->onRequestCallbacks[$className . $method] = $serverName;
|
||||
// 解析回调类
|
||||
$class = $this->container->get($className);
|
||||
// 设置服务名
|
||||
if (method_exists($class, 'setServerName')) {
|
||||
// Override the server name.
|
||||
$class->setServerName($serverName);
|
||||
}
|
||||
// 如果类实现MiddlewareInitializerInterface接口,则调用初始化中间件方法
|
||||
if ($class instanceof MiddlewareInitializerInterface) {
|
||||
$class->initCoreMiddleware($serverName);
|
||||
}
|
||||
$callback = [$class, $method];
|
||||
}
|
||||
// 注册事件回调函数
|
||||
$server->on($event, $callback);
|
||||
}
|
||||
$parameters = array_values($parameters);
|
||||
return new $name(...$parameters);
|
||||
}
|
||||
|
||||
protected function initOption(): void
|
||||
{
|
||||
$ports = $this->container->get(ServerFactory::class)->getConfig()?->getServers();
|
||||
if (! $ports) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($ports as $port) {
|
||||
if ($port->getName() === $this->serverName) {
|
||||
$this->option = $port->getOptions();
|
||||
}
|
||||
}
|
||||
|
||||
$this->option ??= Option::make([]);
|
||||
$this->option->setMustSortMiddlewaresByMiddlewares($this->middlewares);
|
||||
}
|
||||
```
|
||||
|
||||
###### ServerManager::add方法
|
||||
:::
|
||||
::: tip
|
||||
当`http`请求过来时,会触发`request`事件,从注册的事件列表中可知,会调用`Hyperf\HttpServer\Server`的`onRequest`方法。
|
||||
:::
|
||||
|
||||
上面分析完了,继续看下面的代码。
|
||||
:::warning 参考
|
||||
初始化中间件操作,请参考[附录5](./附录5%20初始化中间件){target="_blank"}
|
||||
:::
|
||||
|
||||
接下来设置运行时的一些参数,列表如下,
|
||||
::: details 运行参数
|
||||
|
||||
```php
|
||||
// 设置sever运行时的参数
|
||||
$this->server->set(array_replace($config->getSettings(), $server->getSettings()));
|
||||
// 添加到ServerManager中
|
||||
ServerManager::add($name, [$type, current($this->server->ports)]);
|
||||
Array
|
||||
(
|
||||
[enable_coroutine] => 1
|
||||
[worker_num] => 4
|
||||
[pid_file] => /opt/www/runtime/hyperf.pid
|
||||
[open_tcp_nodelay] => 1
|
||||
[max_coroutine] => 100000
|
||||
[open_http2_protocol] => 1
|
||||
[max_request] => 100000
|
||||
[socket_buffer_size] => 2097152
|
||||
[buffer_output_size] => 2097152
|
||||
[document_root] => /opt/www/public
|
||||
[enable_static_handler] => 1
|
||||
)
|
||||
```
|
||||
|
||||
:::
|
||||
同样的,合并`setting`,`server`配置会替换 `settings`下的某些配置。
|
||||
|
||||
`setting`的具体配置可参考[swoole官方文档](https://wiki.swoole.com/#/server/setting)
|
||||
|
||||
```php
|
||||
$this->server->set(array_replace($config->getSettings(), $server->getSettings()));
|
||||
```
|
||||
|
||||
最后,添加服务信息到`ServerManager`,触发`BeforeMainServerStart`事件
|
||||
|
||||
```php
|
||||
ServerManager::add($name, [$type, current($this->server->ports)]);
|
||||
if (class_exists(BeforeMainServerStart::class)) {
|
||||
// Trigger BeforeMainServerStart event, this event only trigger once before main server start.
|
||||
$this->eventDispatcher->dispatch(new BeforeMainServerStart($this->server, $config->toArray()));
|
||||
}
|
||||
```
|
||||
|
||||
当存在多个`server`时,后续`server`启动,会通过`else`启动,同样的,设置运行参数,注册事件回调,添加信息到`ServerManager`
|
||||
|
||||
```php
|
||||
if (! $this->server instanceof SwooleServer) {
|
||||
$this->server = $this->makeServer($type, $host, $port, $config->getMode(), $sockType);
|
||||
$callbacks = array_replace($this->defaultCallbacks(), $config->getCallbacks(), $callbacks);
|
||||
$this->registerSwooleEvents($this->server, $callbacks, $name);
|
||||
$this->server->set(array_replace($config->getSettings(), $server->getSettings()));
|
||||
ServerManager::add($name, [$type, current($this->server->ports)]);
|
||||
|
||||
if (class_exists(BeforeMainServerStart::class)) {
|
||||
// Trigger BeforeMainServerStart event, this event only trigger once before main server start.
|
||||
$this->eventDispatcher->dispatch(new BeforeMainServerStart($this->server, $config->toArray()));
|
||||
}
|
||||
} else { // [!code focus:13]
|
||||
/** @var bool|SwoolePort $slaveServer */
|
||||
// 添加监听端口
|
||||
$slaveServer = $this->server->addlistener($host, $port, $sockType);
|
||||
if (! $slaveServer) {
|
||||
throw new \RuntimeException("Failed to listen server port [{$host}:{$port}]");
|
||||
}
|
||||
// 获取服务配置
|
||||
$server->getSettings() && $slaveServer->set(array_replace($config->getSettings(), $server->getSettings()));
|
||||
// 注册回调事件
|
||||
$this->registerSwooleEvents($slaveServer, $callbacks, $name);
|
||||
ServerManager::add($name, [$type, $slaveServer]);
|
||||
}
|
||||
```
|
||||
|
||||
`initServers`方法执行完成,返回自身
|
||||
|
||||
```php
|
||||
public function init(ServerConfig $config): ServerInterface
|
||||
{
|
||||
$this->initServers($config);
|
||||
|
||||
return $this; // [!code focus]
|
||||
}
|
||||
```
|
||||
|
||||
###### startServer
|
||||
|
||||
至此,`Hyperf\Server\Server`的`init`方法走完,返回自身实例。
|
||||
`Hyperf\Server\ServerFactory`工厂类`configure`方法完成。
|
||||
回到`StartServer`类的`execute`方法。
|
||||
|
||||
该方法的`$serverFactory->configure($serverConfig);`这一行执行完成。
|
||||
|
||||
```php
|
||||
//
|
||||
Coroutine::set(['hook_flags' => swoole_hook_flags()]);
|
||||
```
|
||||
|
||||
##### start方法
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$this->checkEnvironment($output);
|
||||
|
||||
$serverFactory = $this->container->get(ServerFactory::class)
|
||||
->setEventDispatcher($this->container->get(EventDispatcherInterface::class))
|
||||
->setLogger($this->container->get(StdoutLoggerInterface::class));
|
||||
|
||||
$serverConfig = $this->container->get(ConfigInterface::class)->get('server', []);
|
||||
if (! $serverConfig) {
|
||||
throw new InvalidArgumentException('At least one server should be defined.');
|
||||
}
|
||||
|
||||
$serverFactory->configure($serverConfig);
|
||||
|
||||
Coroutine::set(['hook_flags' => swoole_hook_flags()]);
|
||||
|
||||
$serverFactory->start(); // [!code focus]
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
::: tip
|
||||
该方法的`$serverFactory->configure($serverConfig);`这一行执行完成,返回`Hyperf\Server\Server`对象,然后调用`start`方法,启动服务。
|
||||
:::
|
||||
#### start方法
|
||||
|
||||
终于可以启动服务了,
|
||||
> 文件位置:/vendor/hyperf/server/src/ServerFactory.php
|
||||
|
||||
```php
|
||||
$serverFactory->start();
|
||||
|
||||
public function start(): void
|
||||
{
|
||||
$this->getServer()->start();
|
||||
@ -1315,5 +1645,7 @@ public function start(): void
|
||||
}
|
||||
```
|
||||
|
||||
::: tip
|
||||
其中`$this->server`对应的是`Swoole\Server`实例。调用`start`方法,实际就是启动`Swoole`的服务。
|
||||
此时`server`启动,等待请求。
|
||||
:::
|
||||
|
@ -1,9 +1,12 @@
|
||||
---
|
||||
title: 请求
|
||||
title: 接收请求
|
||||
---
|
||||
# 接收请求
|
||||
|
||||
由前一节可知,事件的注册在`Hyerf\Server\Server`类的`registerSwooleEvents`方法中完成。
|
||||
|
||||
![](https://oss.xiaokeaii.top/2024/event.png)
|
||||
|
||||
注册的回调事件的执行顺序如下:
|
||||
| 所属类 | 事件 | 描述 | 触发时机 | 触发顺序 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
@ -14,14 +17,18 @@ title: 请求
|
||||
| WorkerExitCallback | onWorkerExit | 当 worker 进程退出后触发 | 仅当 worker 进程退出后触发 | 5 |
|
||||
| Server | onRequest | 当接收到请求时触发 | 仅当 worker 进程接收到请求后触发 | 6 |
|
||||
| PipeMessageCallback | onPipeMessage | 当接收到消息时触发 | 仅当 worker 进程接收到消息后触发 | 7 |
|
||||
> 要理解上面事件,请参考`Swoole`的运行流程。
|
||||
::: tip
|
||||
要理解上面事件,请参考`Swoole`的运行流程。
|
||||
:::
|
||||
### Swoole流程
|
||||
|
||||
首先了解`Swoole`的运行流程,(图源网络)
|
||||
![](https://oss.xiaokeaii.top/2024/swoole流程.jpg)
|
||||
具体内容参考[swoole官网](https://wiki.swoole.com/)
|
||||
|
||||
当请求过来时,会触发`onRequest`事件,然后执行`onRequest`回调函数。
|
||||
|
||||
::: tip
|
||||
当请求过来时,会触发`Request`事件,基于之前准备阶段注册的`swoole`事件可知,会调用`Hyperf\HttpServer\Server`类的`onRequest`函数。
|
||||
:::
|
||||
### OnRequest方法
|
||||
|
||||
```php
|
607
src/hyperf/附录5 初始化中间件.md
Normal file
607
src/hyperf/附录5 初始化中间件.md
Normal file
@ -0,0 +1,607 @@
|
||||
---
|
||||
title: 附录5 初始化中间件
|
||||
---
|
||||
# 初始化中间件
|
||||
|
||||
在注册服务,注册服务的事件时,有一个初始化中间件的操作。
|
||||
|
||||
```php
|
||||
protected function registerSwooleEvents(SwoolePort|SwooleServer $server, array $events, string $serverName): void
|
||||
{
|
||||
foreach ($events as $event => $callback) {
|
||||
if (! Event::isSwooleEvent($event)) {
|
||||
continue;
|
||||
}
|
||||
if (is_array($callback)) {
|
||||
// 获取事件对应class和回调方法
|
||||
[$className, $method] = $callback;
|
||||
if (array_key_exists($className . $method, $this->onRequestCallbacks)) {
|
||||
$this->logger->warning(sprintf('%s will be replaced by %s. Each server should have its own onRequest callback. Please check your configs.', $this->onRequestCallbacks[$className . $method], $serverName));
|
||||
}
|
||||
// 记录回调
|
||||
$this->onRequestCallbacks[$className . $method] = $serverName;
|
||||
// 解析回调类
|
||||
$class = $this->container->get($className);
|
||||
// 设置服务名
|
||||
if (method_exists($class, 'setServerName')) {
|
||||
// Override the server name.
|
||||
$class->setServerName($serverName);
|
||||
}
|
||||
// 如果类实现MiddlewareInitializerInterface接口,则调用初始化中间件方法 // [!code focus:4]
|
||||
if ($class instanceof MiddlewareInitializerInterface) {
|
||||
$class->initCoreMiddleware($serverName);
|
||||
}
|
||||
$callback = [$class, $method];
|
||||
}
|
||||
// 注册事件回调函数
|
||||
$server->on($event, $callback);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
其中,默认注册的回调事件有以下几种,我们看`request`回调,其中回调的类是`Hyperf\HttpServer\Server`类,
|
||||
::: details 回调事件
|
||||
|
||||
```php
|
||||
Array
|
||||
(
|
||||
[start] => Array
|
||||
(
|
||||
[0] => Hyperf\Framework\Bootstrap\StartCallback
|
||||
[1] => onStart
|
||||
)
|
||||
|
||||
[managerStart] => Array
|
||||
(
|
||||
[0] => Hyperf\Framework\Bootstrap\ManagerStartCallback
|
||||
[1] => onManagerStart
|
||||
)
|
||||
|
||||
[workerStart] => Array
|
||||
(
|
||||
[0] => Hyperf\Framework\Bootstrap\WorkerStartCallback
|
||||
[1] => onWorkerStart
|
||||
)
|
||||
|
||||
[workerStop] => Array
|
||||
(
|
||||
[0] => Hyperf\Framework\Bootstrap\WorkerStopCallback
|
||||
[1] => onWorkerStop
|
||||
)
|
||||
|
||||
[workerExit] => Array
|
||||
(
|
||||
[0] => Hyperf\Framework\Bootstrap\WorkerExitCallback
|
||||
[1] => onWorkerExit
|
||||
)
|
||||
|
||||
[pipeMessage] => Array
|
||||
(
|
||||
[0] => Hyperf\Framework\Bootstrap\PipeMessageCallback
|
||||
[1] => onPipeMessage
|
||||
)
|
||||
|
||||
[request] => Array
|
||||
(
|
||||
[0] => Hyperf\HttpServer\Server
|
||||
[1] => onRequest
|
||||
)
|
||||
|
||||
)
|
||||
```
|
||||
|
||||
:::
|
||||
查看`Hyperf\HttpServer\Server`类,
|
||||
::: details `Hyperf\HttpServer\Server`
|
||||
|
||||
```php
|
||||
namespace Hyperf\HttpServer;
|
||||
|
||||
use FastRoute\Dispatcher;
|
||||
use Hyperf\Context\RequestContext;
|
||||
use Hyperf\Context\ResponseContext;
|
||||
use Hyperf\Contract\ConfigInterface;
|
||||
use Hyperf\Contract\MiddlewareInitializerInterface;
|
||||
use Hyperf\Contract\OnRequestInterface;
|
||||
use Hyperf\Coordinator\Constants;
|
||||
use Hyperf\Coordinator\CoordinatorManager;
|
||||
use Hyperf\Dispatcher\HttpDispatcher;
|
||||
use Hyperf\Engine\Http\WritableConnection;
|
||||
use Hyperf\ExceptionHandler\ExceptionHandlerDispatcher;
|
||||
use Hyperf\HttpMessage\Server\Request as Psr7Request;
|
||||
use Hyperf\HttpMessage\Server\Response as Psr7Response;
|
||||
use Hyperf\HttpServer\Contract\CoreMiddlewareInterface;
|
||||
use Hyperf\HttpServer\Event\RequestHandled;
|
||||
use Hyperf\HttpServer\Event\RequestReceived;
|
||||
use Hyperf\HttpServer\Event\RequestTerminated;
|
||||
use Hyperf\HttpServer\Exception\Handler\HttpExceptionHandler;
|
||||
use Hyperf\HttpServer\Router\Dispatched;
|
||||
use Hyperf\HttpServer\Router\DispatcherFactory;
|
||||
use Hyperf\Server\Option;
|
||||
use Hyperf\Server\ServerFactory;
|
||||
use Hyperf\Support\SafeCaller;
|
||||
use Psr\Container\ContainerInterface;
|
||||
use Psr\EventDispatcher\EventDispatcherInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Throwable;
|
||||
|
||||
use function Hyperf\Coroutine\defer;
|
||||
use function Hyperf\Support\make;
|
||||
|
||||
//该类实现了MiddlewareInitializerInterface接口 // [!code focus:2]
|
||||
class Server implements OnRequestInterface, MiddlewareInitializerInterface
|
||||
{
|
||||
protected array $middlewares = [];
|
||||
|
||||
protected ?CoreMiddlewareInterface $coreMiddleware = null;
|
||||
|
||||
protected array $exceptionHandlers = [];
|
||||
|
||||
protected ?string $serverName = null;
|
||||
|
||||
protected ?EventDispatcherInterface $event = null;
|
||||
|
||||
protected ?Option $option = null;
|
||||
|
||||
public function __construct(
|
||||
protected ContainerInterface $container,
|
||||
protected HttpDispatcher $dispatcher,
|
||||
protected ExceptionHandlerDispatcher $exceptionHandlerDispatcher,
|
||||
protected ResponseEmitter $responseEmitter
|
||||
) {
|
||||
if ($this->container->has(EventDispatcherInterface::class)) {
|
||||
$this->event = $this->container->get(EventDispatcherInterface::class);
|
||||
}
|
||||
}
|
||||
//....
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
:::
|
||||
所以该类会调用`initCoreMiddleware`方法,进行中间件的初始化。
|
||||
|
||||
```php
|
||||
$class->initCoreMiddleware($serverName);
|
||||
```
|
||||
|
||||
> 文件位置:/vendor/hyperf/http-server/src/Server.php
|
||||
|
||||
```php
|
||||
public function initCoreMiddleware(string $serverName): void
|
||||
{
|
||||
// http
|
||||
$this->serverName = $serverName;
|
||||
// 创建核心中间件对象实例
|
||||
$this->coreMiddleware = $this->createCoreMiddleware();
|
||||
|
||||
$config = $this->container->get(ConfigInterface::class);
|
||||
// 获取配置的中间件
|
||||
$this->middlewares = $config->get('middlewares.' . $serverName, []);
|
||||
// 设置异常处理器
|
||||
$this->exceptionHandlers = $config->get('exceptions.handler.' . $serverName, $this->getDefaultExceptionHandler());
|
||||
// 设置服务的option选项,对中间件进行排序
|
||||
$this->initOption();
|
||||
}
|
||||
```
|
||||
|
||||
## 创建中间件对象实例
|
||||
|
||||
首先创建核心中间件对象实例,通过`make`方法创建。
|
||||
|
||||
```php
|
||||
protected function createCoreMiddleware(): CoreMiddlewareInterface // [!code focus:4]
|
||||
{
|
||||
return make(CoreMiddleware::class, [$this->container, $this->serverName]);
|
||||
}
|
||||
|
||||
|
||||
function make(string $name, array $parameters = [])
|
||||
{
|
||||
if (ApplicationContext::hasContainer()) {
|
||||
/** @var \Hyperf\Di\Container $container */
|
||||
$container = ApplicationContext::getContainer();
|
||||
if (method_exists($container, 'make')) {
|
||||
return $container->make($name, $parameters);
|
||||
}
|
||||
}
|
||||
$parameters = array_values($parameters);
|
||||
return new $name(...$parameters);
|
||||
}
|
||||
|
||||
protected function initOption(): void
|
||||
{
|
||||
$ports = $this->container->get(ServerFactory::class)->getConfig()?->getServers();
|
||||
if (! $ports) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($ports as $port) {
|
||||
if ($port->getName() === $this->serverName) {
|
||||
$this->option = $port->getOptions();
|
||||
}
|
||||
}
|
||||
|
||||
$this->option ??= Option::make([]);
|
||||
$this->option->setMustSortMiddlewaresByMiddlewares($this->middlewares);
|
||||
}
|
||||
```
|
||||
|
||||
实际上`make`方法还是从依赖注入容器中使用`make`方法创建对象。
|
||||
|
||||
### CoreMiddleware实例化过程
|
||||
|
||||
::: code-group
|
||||
```php [构造函数]
|
||||
public function __construct(protected ContainerInterface $container, private string $serverName)
|
||||
{
|
||||
// 创建调度器
|
||||
$this->dispatcher = $this->createDispatcher($serverName);
|
||||
// 获取标准化接口实例
|
||||
$this->normalizer = $this->container->get(NormalizerInterface::class);
|
||||
// 获取方法定义收集器实例
|
||||
$this->methodDefinitionCollector = $this->container->get(MethodDefinitionCollectorInterface::class);
|
||||
// 如果存在,获取闭包定义收集器实例
|
||||
if ($this->container->has(ClosureDefinitionCollectorInterface::class)) {
|
||||
$this->closureDefinitionCollector = $this->container->get(ClosureDefinitionCollectorInterface::class);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected function createDispatcher(string $serverName): Dispatcher
|
||||
{
|
||||
// 从容器中获取DispatcherFactory实例
|
||||
$factory = $this->container->get(DispatcherFactory::class);
|
||||
// 获取调度器实例
|
||||
return $factory->getDispatcher($serverName);
|
||||
}
|
||||
```
|
||||
```php [CoreMiddleware类源码]
|
||||
namespace Hyperf\HttpServer;
|
||||
|
||||
use Closure;
|
||||
use FastRoute\Dispatcher;
|
||||
use Hyperf\Codec\Json;
|
||||
use Hyperf\Context\Context;
|
||||
use Hyperf\Context\RequestContext;
|
||||
use Hyperf\Context\ResponseContext;
|
||||
use Hyperf\Contract\Arrayable;
|
||||
use Hyperf\Contract\Jsonable;
|
||||
use Hyperf\Contract\NormalizerInterface;
|
||||
use Hyperf\Di\ClosureDefinitionCollectorInterface;
|
||||
use Hyperf\Di\MethodDefinitionCollectorInterface;
|
||||
use Hyperf\Di\ReflectionType;
|
||||
use Hyperf\HttpMessage\Exception\MethodNotAllowedHttpException;
|
||||
use Hyperf\HttpMessage\Exception\NotFoundHttpException;
|
||||
use Hyperf\HttpMessage\Exception\ServerErrorHttpException;
|
||||
use Hyperf\HttpMessage\Server\ResponsePlusProxy;
|
||||
use Hyperf\HttpMessage\Stream\SwooleStream;
|
||||
use Hyperf\HttpServer\Contract\CoreMiddlewareInterface;
|
||||
use Hyperf\HttpServer\Router\Dispatched;
|
||||
use Hyperf\HttpServer\Router\DispatcherFactory;
|
||||
use Hyperf\Server\Exception\ServerException;
|
||||
use InvalidArgumentException;
|
||||
use Psr\Container\ContainerInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Psr\Http\Server\RequestHandlerInterface;
|
||||
use RuntimeException;
|
||||
use Swow\Psr7\Message\ResponsePlusInterface;
|
||||
|
||||
class CoreMiddleware implements CoreMiddlewareInterface
|
||||
{
|
||||
protected Dispatcher $dispatcher;
|
||||
|
||||
private MethodDefinitionCollectorInterface $methodDefinitionCollector;
|
||||
|
||||
private ?ClosureDefinitionCollectorInterface $closureDefinitionCollector = null;
|
||||
|
||||
private NormalizerInterface $normalizer;
|
||||
|
||||
public function __construct(protected ContainerInterface $container, private string $serverName)
|
||||
{
|
||||
$this->dispatcher = $this->createDispatcher($serverName);
|
||||
$this->normalizer = $this->container->get(NormalizerInterface::class);
|
||||
$this->methodDefinitionCollector = $this->container->get(MethodDefinitionCollectorInterface::class);
|
||||
if ($this->container->has(ClosureDefinitionCollectorInterface::class)) {
|
||||
$this->closureDefinitionCollector = $this->container->get(ClosureDefinitionCollectorInterface::class);
|
||||
}
|
||||
}
|
||||
|
||||
public function dispatch(ServerRequestInterface $request): ServerRequestInterface
|
||||
{
|
||||
$routes = $this->dispatcher->dispatch($request->getMethod(), $request->getUri()->getPath());
|
||||
|
||||
$dispatched = new Dispatched($routes, $this->serverName);
|
||||
|
||||
return RequestContext::set($request)->setAttribute(Dispatched::class, $dispatched);
|
||||
}
|
||||
|
||||
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
|
||||
{
|
||||
$request = RequestContext::set($request);
|
||||
|
||||
/** @var Dispatched $dispatched */
|
||||
$dispatched = $request->getAttribute(Dispatched::class);
|
||||
|
||||
if (! $dispatched instanceof Dispatched) {
|
||||
throw new ServerException(sprintf('The dispatched object is not a %s object.', Dispatched::class));
|
||||
}
|
||||
|
||||
$response = match ($dispatched->status) {
|
||||
Dispatcher::NOT_FOUND => $this->handleNotFound($request),
|
||||
Dispatcher::METHOD_NOT_ALLOWED => $this->handleMethodNotAllowed($dispatched->params, $request),
|
||||
Dispatcher::FOUND => $this->handleFound($dispatched, $request),
|
||||
default => null,
|
||||
};
|
||||
|
||||
if (! $response instanceof ResponsePlusInterface) {
|
||||
$response = $this->transferToResponse($response, $request);
|
||||
}
|
||||
|
||||
return $response->addHeader('Server', 'Hyperf');
|
||||
}
|
||||
|
||||
public function getMethodDefinitionCollector(): MethodDefinitionCollectorInterface
|
||||
{
|
||||
return $this->methodDefinitionCollector;
|
||||
}
|
||||
|
||||
public function getClosureDefinitionCollector(): ClosureDefinitionCollectorInterface
|
||||
{
|
||||
return $this->closureDefinitionCollector;
|
||||
}
|
||||
|
||||
public function getNormalizer(): NormalizerInterface
|
||||
{
|
||||
return $this->normalizer;
|
||||
}
|
||||
|
||||
protected function createDispatcher(string $serverName): Dispatcher
|
||||
{
|
||||
$factory = $this->container->get(DispatcherFactory::class);
|
||||
return $factory->getDispatcher($serverName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the response when found.
|
||||
*
|
||||
* @return array|Arrayable|mixed|ResponseInterface|string
|
||||
*/
|
||||
protected function handleFound(Dispatched $dispatched, ServerRequestInterface $request): mixed
|
||||
{
|
||||
if ($dispatched->handler->callback instanceof Closure) {
|
||||
$parameters = $this->parseClosureParameters($dispatched->handler->callback, $dispatched->params);
|
||||
$callback = $dispatched->handler->callback;
|
||||
$response = $callback(...$parameters);
|
||||
} else {
|
||||
[$controller, $action] = $this->prepareHandler($dispatched->handler->callback);
|
||||
$controllerInstance = $this->container->get($controller);
|
||||
if (! method_exists($controllerInstance, $action)) {
|
||||
// Route found, but the handler does not exist.
|
||||
throw new ServerErrorHttpException('Method of class does not exist.');
|
||||
}
|
||||
$parameters = $this->parseMethodParameters($controller, $action, $dispatched->params);
|
||||
$response = $controllerInstance->{$action}(...$parameters);
|
||||
}
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the response when cannot found any routes.
|
||||
*/
|
||||
protected function handleNotFound(ServerRequestInterface $request): mixed
|
||||
{
|
||||
throw new NotFoundHttpException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the response when the routes found but doesn't match any available methods.
|
||||
*/
|
||||
protected function handleMethodNotAllowed(array $methods, ServerRequestInterface $request): mixed
|
||||
{
|
||||
throw new MethodNotAllowedHttpException('Allow: ' . implode(', ', $methods));
|
||||
}
|
||||
|
||||
protected function prepareHandler(array|string $handler): array
|
||||
{
|
||||
if (is_string($handler)) {
|
||||
if (str_contains($handler, '@')) {
|
||||
return explode('@', $handler);
|
||||
}
|
||||
if (str_contains($handler, '::')) {
|
||||
return explode('::', $handler);
|
||||
}
|
||||
return [$handler, '__invoke'];
|
||||
}
|
||||
if (is_array($handler) && isset($handler[0], $handler[1])) {
|
||||
return $handler;
|
||||
}
|
||||
throw new RuntimeException('Handler not exist.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Transfer the non-standard response content to a standard response object.
|
||||
*
|
||||
* @param null|array|Arrayable|Jsonable|ResponseInterface|string $response
|
||||
*/
|
||||
protected function transferToResponse($response, ServerRequestInterface $request): ResponsePlusInterface
|
||||
{
|
||||
if (is_string($response)) {
|
||||
return $this->response()->addHeader('content-type', 'text/plain')->setBody(new SwooleStream($response));
|
||||
}
|
||||
|
||||
if ($response instanceof ResponseInterface) {
|
||||
return new ResponsePlusProxy($response);
|
||||
}
|
||||
|
||||
if (is_array($response) || $response instanceof Arrayable) {
|
||||
return $this->response()
|
||||
->addHeader('content-type', 'application/json')
|
||||
->setBody(new SwooleStream(Json::encode($response)));
|
||||
}
|
||||
|
||||
if ($response instanceof Jsonable) {
|
||||
return $this->response()
|
||||
->addHeader('content-type', 'application/json')
|
||||
->setBody(new SwooleStream((string) $response));
|
||||
}
|
||||
|
||||
if ($this->response()->hasHeader('content-type')) {
|
||||
return $this->response()->setBody(new SwooleStream((string) $response));
|
||||
}
|
||||
|
||||
return $this->response()->addHeader('content-type', 'text/plain')->setBody(new SwooleStream((string) $response));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get response instance from context.
|
||||
*/
|
||||
protected function response(): ResponsePlusInterface
|
||||
{
|
||||
return ResponseContext::get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the parameters of method definitions, and then bind the specified arguments or
|
||||
* get the value from DI container, combine to an argument array that should be injected
|
||||
* and return the array.
|
||||
*/
|
||||
protected function parseMethodParameters(string $controller, string $action, array $arguments): array
|
||||
{
|
||||
$definitions = $this->getMethodDefinitionCollector()->getParameters($controller, $action);
|
||||
return $this->getInjections($definitions, "{$controller}::{$action}", $arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the parameters of closure definitions, and then bind the specified arguments or
|
||||
* get the value from DI container, combine to an argument array that should be injected
|
||||
* and return the array.
|
||||
*/
|
||||
protected function parseClosureParameters(Closure $closure, array $arguments): array
|
||||
{
|
||||
if (! $this->container->has(ClosureDefinitionCollectorInterface::class)) {
|
||||
return [];
|
||||
}
|
||||
$definitions = $this->getClosureDefinitionCollector()->getParameters($closure);
|
||||
return $this->getInjections($definitions, 'Closure', $arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ReflectionType[] $definitions
|
||||
*/
|
||||
private function getInjections(array $definitions, string $callableName, array $arguments): array
|
||||
{
|
||||
$injections = [];
|
||||
foreach ($definitions as $pos => $definition) {
|
||||
$value = $arguments[$pos] ?? $arguments[$definition->getMeta('name')] ?? null;
|
||||
if ($value === null) {
|
||||
if ($definition->getMeta('defaultValueAvailable')) {
|
||||
$injections[] = $definition->getMeta('defaultValue');
|
||||
} elseif ($this->container->has($definition->getName())) {
|
||||
$injections[] = $this->container->get($definition->getName());
|
||||
} elseif ($definition->allowsNull()) {
|
||||
$injections[] = null;
|
||||
} else {
|
||||
throw new InvalidArgumentException("Parameter '{$definition->getMeta('name')}' "
|
||||
. "of {$callableName} should not be null");
|
||||
}
|
||||
} else {
|
||||
$injections[] = $this->getNormalizer()->denormalize($value, $definition->getName());
|
||||
}
|
||||
}
|
||||
return $injections;
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
:::
|
||||
|
||||
`DispatcherFactory`类在实例化时,调用构造方法,进行初始化路由和调度器
|
||||
```php
|
||||
public function __construct()
|
||||
{
|
||||
// 根据注解初始化路由
|
||||
$this->initAnnotationRoute(AnnotationCollector::list());
|
||||
// 根据配置文件初始化路由
|
||||
$this->initConfigRoute();
|
||||
}
|
||||
|
||||
public function getDispatcher(string $serverName): Dispatcher
|
||||
{
|
||||
if (isset($this->dispatchers[$serverName])) {
|
||||
return $this->dispatchers[$serverName];
|
||||
}
|
||||
|
||||
$router = $this->getRouter($serverName);
|
||||
return $this->dispatchers[$serverName] = new GroupCountBased($router->getData());
|
||||
}
|
||||
```
|
||||
CoreMiddleware实例化完成。
|
||||
|
||||
```php
|
||||
|
||||
public function initCoreMiddleware(string $serverName): void
|
||||
{
|
||||
$this->serverName = $serverName;
|
||||
// 这里保存了所有的路由信息
|
||||
$this->coreMiddleware = $this->createCoreMiddleware();
|
||||
// 获取配置文件
|
||||
$config = $this->container->get(ConfigInterface::class); // [!code focus:5]
|
||||
// 设置配置的中间件数组
|
||||
$this->middlewares = $config->get('middlewares.' . $serverName, []);
|
||||
// 设置异常处理器
|
||||
$this->exceptionHandlers = $config->get('exceptions.handler.' . $serverName, $this->getDefaultExceptionHandler());
|
||||
|
||||
$this->initOption();
|
||||
}
|
||||
```
|
||||
### 设置异常处理器
|
||||
配置服务的异常处理程序,首先从配置文件`exceptions`中,获取配置的异常处理器,如不存在,则使用默认的异常处理器。
|
||||
```php
|
||||
$this->exceptionHandlers = $config->get('exceptions.handler.' . $serverName, $this->getDefaultExceptionHandler());
|
||||
|
||||
protected function getDefaultExceptionHandler(): array
|
||||
{
|
||||
return [
|
||||
HttpExceptionHandler::class,
|
||||
];
|
||||
}
|
||||
```
|
||||
|
||||
### 初始化配置
|
||||
设置`Server`的`option`参数
|
||||
```php
|
||||
|
||||
protected function initOption(): void
|
||||
{
|
||||
// 获取服务器配置对象数组,类型为port[]
|
||||
$ports = $this->container->get(ServerFactory::class)->getConfig()?->getServers();
|
||||
if (! $ports) {
|
||||
return;
|
||||
}
|
||||
// 设置服务的option配置
|
||||
foreach ($ports as $port) {
|
||||
if ($port->getName() === $this->serverName) {
|
||||
$this->option = $port->getOptions();
|
||||
}
|
||||
}
|
||||
|
||||
$this->option ??= Option::make([]);
|
||||
// 对中间件进行排序
|
||||
$this->option->setMustSortMiddlewaresByMiddlewares($this->middlewares);
|
||||
}
|
||||
|
||||
// 如果设置了顺序比如[foo::class => 1]或者继承了PriorityMiddleware中间件,都将启动中间件的排序操作
|
||||
public function setMustSortMiddlewaresByMiddlewares(array $middlewares): static
|
||||
{
|
||||
foreach ($middlewares as $middleware) {
|
||||
if (is_int($middleware) || $middleware instanceof PriorityMiddleware) {
|
||||
return $this->setMustSortMiddlewares(true);
|
||||
}
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
```
|
||||
最后,初始化中间件完成,等待`http`请求。
|
Loading…
Reference in New Issue
Block a user