swoft 启动流程之二

swoft&swoole

前面我们说到了 Application 对象实例的创建,接下来我们来看下 run() 方法中各类处理器的handle() 实现

1、EnvProcessor 这个是加载根目录下的.env 配置文件,在这之后就可以使用 env 函数获取相应的配置了;详细可以看 https://github.com/vlucas/phpdotenv,这里就不再赘述

2、ConfigProcessor 这个处理器仅仅是定义如下两个常量,还不能使用 config 函数获取配置项:

/**
     * Define constant
     */
    protected function defineConstant(): void
    {
        // Define some global constants
        define('APP_DEBUG', (int)env('APP_DEBUG', 0));
        define('SWOFT_DEBUG', (int)env('SWOFT_DEBUG', 0));
    }

3、AnnotationProcessor 注解处理器,主要是用来加载 swoft 下面各模块的注解处理类

public function handle(): bool
    {
        if (!$this->application->beforeAnnotation()) {
            CLog::warning('Stop annotation processor by beforeAnnotation return false');
            return false;
        }

        $app = $this->application;

        // Find AutoLoader classes. Parse and collect annotations.
        AnnotationRegister::load([
            'inPhar'               => \IN_PHAR, // 是否启用了phar打包程序
            'basePath'             => $app->getBasePath(), // 项目根目录
            'notifyHandler'        => [$this, 'notifyHandler'],
            'disabledAutoLoaders'  => $app->getDisabledAutoLoaders(),
            'disabledPsr4Prefixes' => $app->getDisabledPsr4Prefixes(),
        ]);
        // 最终是使用 vendor/swoft/annotation/src/Resource/AnnotationResource.php 类文件进行加载

        $stats = AnnotationRegister::getClassStats();

        CLog::info(
            'Annotations is scanned(autoloader %d, annotation %d, parser %d)',
            $stats['autoloader'],
            $stats['annotation'],
            $stats['parser']
        );

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

AnnotationResource 类的 load方法:

/**
     * Load annotation resource by find ClassLoader
     *
     * @throws AnnotationException
     * @throws ReflectionException
     */
// 这个是通过 vendor/composer/autoload_psr4.php 文件里面的命名空间和目录加载相应组件下的 Autoloader.php 类文件,可以进入swoft框架的任意一个组件,都会有 Autoloader.php 文件
    public function load(): void
    {
        $prefixDirsPsr4 = $this->classLoader->getPrefixesPsr4();

        foreach ($prefixDirsPsr4 as $ns => $paths) {
            // Only scan namespaces
            if ($this->onlyNamespaces && !in_array($ns, $this->onlyNamespaces, true)) {
                $this->notify('excludeNs', $ns);
                continue;
            }

            // It is excluded psr4 prefix
            if ($this->isExcludedPsr4Prefix($ns)) {
                AnnotationRegister::registerExcludeNs($ns);
                $this->notify('excludeNs', $ns);
                continue;
            }

            // Find package/component loader class
            foreach ($paths as $path) {
                $loaderFile = $this->getAnnotationClassLoaderFile($path);
                if (!file_exists($loaderFile)) {
                    $this->notify('noLoaderFile', $this->clearBasePath($path), $loaderFile);
                    continue;
                }

                $loaderClass = $this->getAnnotationLoaderClassName($ns);
               // 通过使用 class_exists 触发自动加载机制把对应的 Autoloader 类加载进来
                if (!class_exists($loaderClass)) {
                    $this->notify('noLoaderClass', $loaderClass);
                    continue;
                }

                $loaderObject = new $loaderClass();
                if (!$loaderObject instanceof LoaderInterface) {
                    $this->notify('invalidLoader', $loaderFile);
                    continue;
                }

                $this->notify('findLoaderClass', $this->clearBasePath($loaderFile));

                // If is disable, will skip scan annotation classes
                if (!isset($this->disabledAutoLoaders[$loaderClass])) {

// 标记改文件已经被加载过                    AnnotationRegister::registerAutoLoaderFile($loaderFile);
                    $this->notify('addLoaderClass', $loaderClass);
                    // 关键中的关键,通过遍历所有组件的文件夹,把以php结尾的类文件全部加载到内存中,除被排除加载的文件。并且这个时候还会把 app 下的所有类文件进行加载
                    $this->loadAnnotation($loaderObject);
                }

                // Storage auto loader to register
                // 注册各组件的自动加载器
                AnnotationRegister::addAutoLoader($ns, $loaderObject);
            }
        }
    }

// 加载进来后 对每个 类文件进行注解分析,代码见下面:
/**
     * Parser annotation
     *
     * @param string $namespace
     * @param string $className
     *
     * @throws AnnotationException
     * @throws ReflectionException
     */
    private function parseAnnotation(string $namespace, string $className): void
    {
        // Annotation reader
        // 通过反射获取类信息
        $reflectionClass = new ReflectionClass($className);

        // Fix ignore abstract
        // 如果是抽象类则跳过
        if ($reflectionClass->isAbstract()) {
            return;
        }
        // 类注解分析
        $oneClassAnnotation = $this->parseOneClassAnnotation($reflectionClass);

        if (!empty($oneClassAnnotation)) {
            AnnotationRegister::registerAnnotation($namespace, $className, $oneClassAnnotation);
        }
    }

4、BeanProcessor Bean 处理器

我直接看该类下的 handle方法:

public function handle(): bool
    {
        if (!$this->application->beforeBean()) {
            return false;
        }

        $handler     = new BeanHandler();
        // 这里是加载已经定义好的 bean(包括 在 beans.php文件和 自动加载
类文件中定义好的 ,例如:
        vendor/swoft/framework/src/AutoLoader.php 下的 
         public function beans(): array
    {
        return [
            'config'             => [
                'class'   => Config::class,
                'path'    => alias('@config'),
                'parsers' => [
                    Config::TYPE_PHP => '${phpParser}'
                ]
            ],
            ... 省略代码,详细可以定位到上述文件中查看
        ];
    }
)
        $definitions = $this->getDefinitions();
        // 这个是 注解解析 器,每一个注解类型都会有一个对应的注解解析器。可以在swoft 每个组件下面看看 Annotation 文件夹
        $parsers     = AnnotationRegister::getParsers();
        // 这个是 所有逻辑代码的注解信息(包括使用到的注解类和反射信息),不包含注解解析器
        $annotations = AnnotationRegister::getAnnotations();
        // 把上面的信息全部添加到Bean工程容器类,并设置处理句柄
        BeanFactory::addDefinitions($definitions);
        BeanFactory::addAnnotations($annotations);
        BeanFactory::addParsers($parsers);
        BeanFactory::setHandler($handler);
        // 这里也是最关键的一步,进行 Bean 的创建等。。。 ,感兴趣的可以跟进去看看
        BeanFactory::init();

        /* @var Config $config*/
        // 这里开始就可以使用 config() 函数来获取配置了,不过这个倒是希望
        // 作者可以提前,这样我们就可以在 beans.php 里面来获取我们的配置了
        $config = BeanFactory::getBean('config');

        CLog::info('config path=%s', $config->getPath());
        CLog::info('config env=%s', $config->getEnv());

        $stats = BeanFactory::getStats();

        CLog::info('Bean is initialized(%s)', SwoftHelper::formatStats($stats));

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

5、EventProcessor 事件处理器

这个主要是 注册事件管理器 EventManager,并把swoft各组件定义下的 事件监听类 与 之绑定的事件绑定在一起。这样我们在相应事件触发的时候就可以把串联起来的事件监听器全部依次执行了

6、ConsoleProcessor 命令行处理器,各种进程启动都在这里面,这个涉及的内容比较多,放在下一章讲解

发表评论

电子邮件地址不会被公开。 必填项已用*标注