Swoft-框架源码阅读-四:基于EventProcessor了解事件管理

上一章的BeanProcessor完成了类的实例化和注入操作。接下来则是 EventProcessor了。EventProcessor完成了对有所Listener和Subscriber事件的注册,以及触发了,监听在应用初始化完毕后的所有事件。
我们来看看代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public function handle(): bool
{
if (!$this->application->beforeEvent()) {
CLog::warning('Stop event processor by beforeEvent return false');
return false;
}

/** @var EventManager $eventManager */
$eventManager = bean('eventManager');
[$count1, $count2] = ListenerRegister::register($eventManager);

CLog::info('Event manager initialized(%d listener, %d subscriber)', $count1, $count2);

// Trigger a app init event
Swoft::trigger(SwoftEvent::APP_INIT_COMPLETE);

return $this->application->afterEvent();
}

由于BeanProcessor完成了注解类的实例化,这里就可以使用bean()函数来直接使用对象。

在这里我们可以清楚的看到,这个方法将所有事件对象,注册至监听事件中。然后触发生命周期为APP_INIT_COMPLETE的所有事件。

那么这个事件管理器的内部实现是怎样的呢?我们接下来就看一看。

Swoft的事件管理

Swoft框架中,整个事件管理的核心是 EventManager。它一个分为两个模块,分别是ListenerSubscriber。这里我们讨论下Listener

我们在ListenerRegister::register()方法中看到,注册时是通过$em->addListener()的方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public static function register(EventManager $em): array
{
foreach (self::$listeners as $className => $eventInfo) {
$listener = Swoft::getSingleton($className);

if (!$listener instanceof EventHandlerInterface) {
throw new RuntimeException("The event listener class '{$className}' must be instanceof EventHandlerInterface");
}

$em->addListener($listener, $eventInfo);
}

// ...
}

遍历静态变量$listeners,取出监听事件类名,然后获取其相应的以实例化好的对象,最后注入到$em->listeners数组中。

到这里可能有人有疑问了,这个self::$listeners的值是哪儿来的?其实这个值在上个AnnotationProcessor中已经完成。

我们知道,注解在初始化时,每个添加上注解的类都会根据其相应的parser做一些解析。观察下./vendor/swoft/event/src/parser目录就会知道。目录下的ListenerParser.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public function parse(int $type, $annotation): array
{
if ($type !== self::TYPE_CLASS) {
throw new AnnotationException('`@Listener` must be defined on class!');
}

// collect listeners
ListenerRegister::addListener($this->className, [
// event name => listener priority
$annotation->getEvent() => $annotation->getPriority()
]);

return [$this->className, $this->className, Bean::SINGLETON, ''];
}

在解析时,它将获取这个类的类名,然后调用注册进ListenerRegister::addListener()方法,将这些注入到ListenerRegister::$listeners中。所以在EventProcessor阶段中,才能遍历$listeners.

回到刚刚的问题$em->addListener()之后,在通过trigger()触发。Swoft在其生命周期的各个点,已经埋好了触发器。就比如在此时是swoft核心功能初始化完毕的时候,于是handle()最后就有Swoft::trigger(SwoftEvent::APP_INIT_COMPLETE),用于触发相关事件。

剩下的关于事件优先级触发的机制,这个部分在ListenerQueue.php的类中可以看到

1
2
3
4
5
public function __construct()
{
$this->store = new SplObjectStorage();
$this->queue = new SplPriorityQueue();
}

相同触发时间的事件,都会放在$this->queue中,而这个成员变量的本质其实是一个SplPriorityQueue(优先队列)。在这里不太了解数据结构,和PHPSPL相关知识的同学,可以去看一下。

总结

这里已经分析了Listener,其实Subscriber的实现方式跟其差不多,大家可以自己去看一下。下一个ConsoleProcessor可讲的不是太多。所以下一篇文章很有可能是对Swoft中的AOP概念的解析。