EasySwoole核心Core分析(二):createServer&start方法
我们之前分析了CommandRunner
类,它会去执行一些具体的命令.当我们输入php easyswoole start
的时候,将会去执行EasySwoole\EasySwoole\Command\DefaultCommand\Start
类中的exec
方法.
public function exec(array $args): ?string
{
// 清除Opcahce缓存和apc缓存
Utility::opCacheClear();
$mode = 'develop';
// 判断是否为dev环境
if (!Core::getInstance()->isDev()) {
$mode = 'produce';
}
// 获取config实例
$conf = Config::getInstance();
// 判断是否为守护进程
if (in_array("d", $args) || in_array("daemonize", $args)) {
$conf->setConf("MAIN_SERVER.SETTING.daemonize", true);
}
// 创建服务
Core::getInstance()->createServer();
...
// 将服务器信息打印在终端
echo $response;
// 启动服务
Core::getInstance()->start();
return null;
}
我们之前都是在初始化日志系统、注册注册错误回调,还没有创建Swoole相关服务,那么创建Swoole实例的部分在哪呢?
Core::getInstance()->createServer()
顾名思义创建服务
function createServer()
{
$conf = Config::getInstance()->getConf('MAIN_SERVER');
// 创建Swoole服务
ServerManager::getInstance()->createSwooleServer(
$conf['PORT'], $conf['SERVER_TYPE'], $conf['LISTEN_ADDRESS'], $conf['SETTING'], $conf['RUN_MODEL'], $conf['SOCK_TYPE']
);
// 注册默认回调事件
$this->registerDefaultCallBack(ServerManager::getInstance()->getSwooleServer(), $conf['SERVER_TYPE']);
// hook 全局的mainServerCreate事件
EasySwooleEvent::mainServerCreate(ServerManager::getInstance()->getMainEventRegister());
// 注册crontab、Task进程
$this->extraHandler();
return $this;
}
ServerManager::getInstance()->createSwooleServer()
这里又使用ServerManager
类的方法,这篇里我们只需要知道它能创建一个Swoole服务即可(后续会专门介绍内部实现)
$this->registerDefaultCallBack()
该方法用于注册主服务的事件,我们知道Swoole的Server有多个事件,我们需要去设置相应的回调.
private function registerDefaultCallBack(\swoole_server $server, int $serverType)
{
// 判断是否为HTTP服务或WebSocket服务, 绑定OnRequest事件
if (in_array($serverType, [EASYSWOOLE_WEB_SERVER, EASYSWOOLE_WEB_SOCKET_SERVER], true)) {
// 获取命名空间
$namespace = Di::getInstance()->get(SysConst::HTTP_CONTROLLER_NAMESPACE);
if (empty($namespace)) {
$namespace = 'App\\HttpController\\';
}
// 获取控制器最大深度
$depth = intval(Di::getInstance()->get(SysConst::HTTP_CONTROLLER_MAX_DEPTH));
$depth = $depth > 5 ? $depth : 5;
// 获取最大数量
$max = intval(Di::getInstance()->get(SysConst::HTTP_CONTROLLER_POOL_MAX_NUM));
z($max);
if ($max == 0) {
$max = 500;
}
// 获取等待时间
$waitTime = intval(Di::getInstance()->get(SysConst::HTTP_CONTROLLER_POOL_WAIT_TIME));
if ($waitTime == 0) {
$waitTime = 5;
}
// 初始化路由分发器
$dispatcher = new Dispatcher($namespace, $depth, $max);
// 设置等待时间
$dispatcher->setControllerPoolWaitTime($waitTime);
// 获取HTTP异常全局处理方式
$httpExceptionHandler = Di::getInstance()->get(SysConst::HTTP_EXCEPTION_HANDLER);
if (!is_callable($httpExceptionHandler)) {
// 不存在全局异常捕获时,将把错误信息输出到页面
$httpExceptionHandler = function ($throwable, $request, $response) {
$response->withStatus(Status::CODE_INTERNAL_SERVER_ERROR);
$response->write(nl2br($throwable->getMessage() . "\n" . $throwable->getTraceAsString()));
Trigger::getInstance()->throwable($throwable);
};
// 注入进容器
Di::getInstance()->set(SysConst::HTTP_EXCEPTION_HANDLER, $httpExceptionHandler);
}
// 为分发器也设置异常处理方法
$dispatcher->setHttpExceptionHandler($httpExceptionHandler);
// 为创建的Server注册Request事件, EventHelper类封装了Swoole的Server的on、add、set方法
EventHelper::on($server, EventRegister::onRequest, function (\swoole_http_request $request, \swoole_http_response $response) use ($dispatcher) {
$request_psr = new Request($request); // 生成PSR请求规范
$response_psr = new Response($response); // 生成PSR响应规范
try {
// 如果为true则分发路由, 这里的onRequest和Swoole的事件是两码事,不要弄混淆了
if (EasySwooleEvent::onRequest($request_psr, $response_psr)) {
// 分发路由, 执行HTTP控制器里__hook方法,将响应结果存入Response对象
$dispatcher->dispatch($request_psr, $response_psr);
}
} catch (\Throwable $throwable) {
call_user_func(Di::getInstance()->get(SysConst::HTTP_EXCEPTION_HANDLER), $throwable, $request_psr, $response_psr);
} finally {
try {
// 处理全局Http afterRequest事件
EasySwooleEvent::afterRequest($request_psr, $response_psr);
} catch (\Throwable $throwable) {
call_user_func(Di::getInstance()->get(SysConst::HTTP_EXCEPTION_HANDLER), $throwable, $request_psr, $response_psr);
}
}
// 响应数据
$response_psr->__response();
});
}
// 获取主服务的事件对象
$register = ServerManager::getInstance()->getMainEventRegister();
//注册进程启动事件
EventHelper::registerWithAdd($register, EventRegister::onWorkerStart, function (\swoole_server $server, $workerId) {
// 为Work进程设置名字
if (!in_array(PHP_OS, ['Darwin', 'CYGWIN', 'WINNT'])) {
$name = Config::getInstance()->getConf('SERVER_NAME');
if (($workerId < Config::getInstance()->getConf('MAIN_SERVER.SETTING.worker_num')) && $workerId >= 0) {
$type = 'Worker';
cli_set_process_title("{$name}.{$type}.{$workerId}");
}
}
});
// 注册进程退出事件
EventHelper::registerWithAdd($register, $register::onWorkerExit, function () {
// 清除当前工作进程内的所有定时器
Timer::clearAll();
});
}
EasySwoole里提供了一个EventRegister
类,里面声明了Swoole Server的事件.
class EventRegister extends MultiContainer
{
const onStart = 'start';
const onShutdown = 'shutdown';
const onWorkerStart = 'workerStart';
const onWorkerStop = 'workerStop';
const onWorkerExit = 'workerExit';
const onTimer = 'timer';
const onConnect = 'connect';
const onReceive = 'receive';
const onPacket = 'packet';
const onClose = 'close';
const onBufferFull = 'bufferFull';
const onBufferEmpty = 'bufferEmpty';
const onTask = 'task';
const onFinish = 'finish';
const onPipeMessage = 'pipeMessage';
const onWorkerError = 'workerError';
const onManagerStart = 'managerStart';
const onManagerStop = 'managerStop';
const onRequest = 'request';
const onHandShake = 'handShake';
const onMessage = 'message';
const onOpen = 'open';
...
}
在registerDefaultCallBack
方法里还会初始化一个Dispatcher
类,该类用于分发请求到相应的控制器.(路由组件基于fastRoute).这里我们只需要知道它是干啥的就可以了.
默认只针对HTTP服务或WebSocket服务创建OnRequset
事件,最后还设置了OnWorkStart
和OnWorkExit
事件,其他服务或者是需要处理其他事件,可以在根目录的EasySwooleEvent
类中mainServerCreate
方法创建,例如是一个websocket服务需要自己注册一个OnMessage
事件,例如:
public static function mainServerCreate(EventRegister $register)
{
$register->set(EventRegister::onMessage, function (\swoole_websocket_server $server, \swoole_websocket_frame $frame) {
$server->push($frame->fd, "over");
});
}
最后在$this->extraHandler
方法里注册crontab和Task进程,到此createServer
方法我们分析完毕.
我们的Start方法调用ServerManager::getInstance()->start()
启动整个服务.到这里我们Swoole实例已经跑起来了.
如果没有仔细跟读源码,会对 DI,ServerManager,Dispatcher,Crontab,TaskManager的实现很模糊,甚至会读不懂上下文.在后续的分析中,会专门分析其具体实现.循序渐进而不是一篇到底.这样可能读起来更困难.
No Comments