hyperf3 框架原理

发布时间 2023-04-17 21:52:59作者: 虎背熊腰

一: hyperf 核心组件

1681737081399.jpg

二: Inject 实现原理

1: 通过InjectAspect代理了Inject注解
2: 具体执行逻辑扫,框架加载开始描所有的类,只要包含Inject注解的都会生成一个proxy类
3: ClassLoader 拦截Composer原始加载类方法,定位到proxy 文件类,通过__handlePropertyHandler 注入Inject注解的属性

代码块一
// Proxy the composer class loader
        foreach ($loaders as &$loader) {
            $unregisterLoader = $loader;
            if (is_array($loader) && $loader[0] instanceof ComposerClassLoader) {
                /** @var ComposerClassLoader $composerClassLoader */
                $composerClassLoader = $loader[0];
                AnnotationRegistry::registerLoader(function ($class) use ($composerClassLoader) {
                    return (bool) $composerClassLoader->findFile($class);
                });
                $loader[0] = new static($composerClassLoader, $proxyFileDirPath, $configDir, $handler);
            }
            spl_autoload_unregister($unregisterLoader);
        }

代码块二
 foreach ($classes as $className => $reflectionClass) {
            $reflectionClassMap[$className] = $reflectionClass->getFileName();
            if ($this->filesystem->lastModified($reflectionClass->getFileName()) >= $lastCacheModified) {
                /** @var MetadataCollector $collector */
                foreach ($collectors as $collector) {
                    $collector::clear($className);
                }

                $this->collect($annotationReader, $reflectionClass);
            }
        }
        $this->loadAspects($lastCacheModified);
      .....
      .....
    // Get the class map of Composer loader
        $classMap = array_merge($reflectionClassMap, $classMap);
        $proxyManager = new ProxyManager($classMap, $proxyDir);
        $proxies = $proxyManager->getProxies();



以IndexController为例
class IndexController extends AbstractController
{
    use \Hyperf\Di\Aop\ProxyTrait;
    use \Hyperf\Di\Aop\PropertyHandlerTrait;
    function __construct()
    {
        if (method_exists(parent::class, '__construct')) {
            parent::__construct(...func_get_args());
        }
        $this->__handlePropertyHandler(__CLASS__);
    }
    /**
     * @Inject()
     * @var BaseService
     */
    public $someService1;
    /**
     * @return array
     */
    public function index()
    {
        $this->someService1->index();
        $user = $this->request->input('user', 'Hyperf');
        $method = $this->request->getMethod();
        //var_dump($this);
        return ['method' => $method, 'message' => "Hello {$user}."];
    }
}

__handlePropertyHandler 就是属性注入逻辑

三: IOC注入分为哪些方式

1: Inject注入
2: 函数或是构造参数注入,无需使用Inject注解

四: Aspect切面实现

1: InjectAspect 比较特殊,不需要执行切面的Process 处理逻辑
2: 通过上述的loadAspects方法生成代理类,在runtime/container/proxy 文件夹下面
3: 执行时通过 self::__proxyCall 拦截运行方法

4: 案例代码块如下

class SomeService extends BaseService
{
    use \Hyperf\Di\Aop\ProxyTrait;
    use \Hyperf\Di\Aop\PropertyHandlerTrait;
    function __construct()
    {
        if (method_exists(parent::class, '__construct')) {
            parent::__construct(...func_get_args());
        }
        $this->__handlePropertyHandler(__CLASS__);
    }
    public function index()
    {
        $__function__ = __FUNCTION__;
        $__method__ = __METHOD__;
        return self::__proxyCall(__CLASS__, __FUNCTION__, self::__getParamsMap(__CLASS__, __FUNCTION__, func_get_args()), function () use($__function__, $__method__) {
        });
    }
}

五:Amqp 的@Consumer 和 apolle启动拉配置实现方式

1: 通过ConfigProvider listeners 参数注入配置,框架启动时会在预设点dispatcher 对应的event 事件注入的观察者
2: 常见的event有
image.png
3: apolle 同理如上
4: 所以实现自定义的插件需要提供ConfigProvider配置文件

六:框架中比较重要的两个命令

1: vendor:publish 用来发布配置文件,tp,laravel都有
2: package:discover 用来注入ServiceProvder,ioc中重要的一环,tp,laravel都有,hyperf 暂时未使用