通过后面2大节的工作,当初容器内曾经保留了残缺的bean定义对象和名称、别名映射.

本章的工作是梳理swoft如何利用bean的定义对象,生成最终可供业务应用的bean对象.

初始化bean的入口办法:

private function initializeBeans(): void{     // 遍历保留的定义对象数组,失去bean名称和定义对象     /* @var ObjectDefinition $objectDefinition */     foreach ($this->objectDefinitions as $beanName => $objectDefinition) {         // 获取定义对象的类型         $scope = $objectDefinition->getScope();         // 如果是request类型         // Exclude request         if ($scope === Bean::REQUEST) {             // 将定义对象转存到request定义对象数组             $this->requestDefinitions[$beanName] = $objectDefinition;             // 从全局定义对象数组中删除这个定义对象             unset($this->objectDefinitions[$beanName]);             // 跳过             continue;          }         // 如果类型是session         // Exclude session         if ($scope === Bean::SESSION) {             // 转存定义对象到session定义对象数组             $this->sessionDefinitions[$beanName] = $objectDefinition;             // 从全局定义对象数组中移除这个定义对象             unset($this->objectDefinitions[$beanName]);             // 跳过             continue;          }         // 创立bean对象         // New bean         $this->newBean($beanName);     }}

创立bean对象:

private function newBean(string $beanName, string $id = ''){     // 首先查看这个bean是否曾经存在,如果存在则间接返回这个bean     // First, check bean whether has been create.     if (isset($this->singletonPool[$beanName]) || isset($this->prototypePool[$beanName])) {        return $this->get($beanName);     }     // 获取定义对象     // Get object definition     $objectDefinition = $this->getNewObjectDefinition($beanName);     // 获取类型     $scope = $objectDefinition->getScope();     // 获取别名     $alias = $objectDefinition->getAlias();     // Cache reflection class info     // 获取定义对象保留的类名     $className = $objectDefinition->getClassName();     // 创立一个新的类反射对象或从缓存中取出这个类的反射对象     $reflectClass = Reflections::cache($className);     // 调用初始化前回调     // Before initialize bean     $this->beforeInit($beanName, $className, $objectDefinition);     // 结构参数     $constructArgs = [];     // 获取结构注入对象     $constructInject = $objectDefinition->getConstructorInjection();     // 如果存在     if ($constructInject !== null) {        // 获取结构参数        $constructArgs = $this->getConstructParams($constructInject, $id);     }     // 如果存在代理类,则将原来的类反射对象替换为代理类的类反射对象     // It's proxy class. eg: AOP, RPC client class     if ($this->handler) {         $oldCName = $className;         $className = $this->handler->classProxy($className);         // New class name from handler->classProxy()         if ($oldCName !== $className) {            $reflectClass = new ReflectionClass($className);         }     }     // 传入反射类和结构参数,创立反射实例     $reflectObject = $this->newInstance($reflectClass, $constructArgs);     // 获取须要注入的属性     $propertyInjects = $objectDefinition->getPropertyInjections();     // 递归从类的最顶层父类开始,顺次遍历属性注入数组,查找须要注入的属性,而后给该属性赋值     // Inject properties values     $this->newProperty($reflectObject, $reflectClass, $propertyInjects, $id);     // Alias name     // Fix: $aliasId !== $id for deny loop get      // 设置bean的别名     if ($alias && $alias !== $beanName) {        $this->aliases[$alias] = $beanName;     }     // 如果反射类有init办法     // Call init method if exist     if ($reflectClass->hasMethod(self::INIT_METHOD)) {        // 调用反射实例的init办法        $reflectObject->{self::INIT_METHOD}();     }     // 将反射实例按bean名称保留在对应类型的对象数组中     // 并依据类型返回对应的实例     return $this->setNewBean($beanName, $scope, $reflectObject, $id);}

保留新bean对象的办法,4中类型别离保留在4个数组中:

private function setNewBean(string $beanName, string $scope, $object, string $id = ''){     switch ($scope) {         case Bean::SINGLETON: // Singleton             $this->singletonPool[$beanName] = $object;             break;          case Bean::PROTOTYPE:             $this->prototypePool[$beanName] = $object;             // Clone it             // 将返回值设置为克隆对象             $object = clone $object;             break;          case Bean::REQUEST:             // 这里的ID应该是申请的协程ID             $this->requestPool[$id][$beanName] = $object;             break;          case Bean::SESSION:             // 这里的ID应该是sessionID             $this->sessionPool[$id][$beanName] = $object;             break;      }     return $object;}

属性注入办法实现:

 private function newProperty( $reflectObject, ReflectionClass $reflectionClass, array $propertyInjects, string $id = '' ): void {     // 获取反射类的父反射类对象     // New parent properties     $parentClass = $reflectionClass->getParentClass();     // 如果有父类,则持续递归,直到找到最顶层父类     if ($parentClass !== false) {        $this->newProperty($reflectObject, $parentClass, $propertyInjects, $id);     }     // 遍历属性注入对象数组     /* @var PropertyInjection $propertyInject */     foreach ($propertyInjects as $propertyInject) {         // 获取属性注入对象标识的属性名         $propertyName = $propertyInject->getPropertyName();         // 如果以后类中没有这个属性名,则跳过后续的注入逻辑         if (!$reflectionClass->hasProperty($propertyName)) {            continue;         }         /** @noinspection PhpUnhandledExceptionInspection */         // 从反射类中获取对应的反射属性对象         $reflectProperty = $reflectionClass->getProperty($propertyName);         // 如果是static类型,则抛出异样         if ($reflectProperty->isStatic()) {            throw new InvalidArgumentException(sprintf('Property %s for bean can not be `static` ', $propertyName));         }         // 获取属性注入对象中保留的value         // Parse property value         $propertyValue = $propertyInject->getValue();         // 如果值是字符串且存在以这个值命名的接口         // Inject interface         if (is_string($propertyValue) && interface_exists($propertyValue)) {            $propertyValue = InterfaceRegister::getInterfaceInjectBean($propertyValue);         } elseif (is_array($propertyValue)) {            // 如果是数组,且数组内存在援用类型            // 则将其替换成            $propertyValue = $this->newPropertyArray($propertyValue, $id);         }         // Refer config or bean         if ($propertyInject->isRef()) {            $propertyValue = $this->getRefValue($propertyValue, $id);            // Optimize: Value not exists, skip call setter             if ($propertyValue === null) {                continue;            }         }         // Parser property type $propertyType = ObjectHelper::getPropertyBaseType($reflectProperty);         if (!empty($propertyType)) {            $propertyValue = ObjectHelper::parseParamType($propertyType, $propertyValue);         }         // First, try set value by setter method         $setter = 'set' . ucfirst($propertyName);         if (method_exists($reflectObject, $setter)) {             $reflectObject->$setter($propertyValue);             continue;          }         if (!$reflectProperty->isPublic()) {            $reflectProperty->setAccessible(true);         }         // Set value by reflection         $reflectProperty->setValue($reflectObject, $propertyValue);     } }

解决数组参数的办法:

private function newPropertyArray(array $propertyValue, string $id = ''): array{     // 遍历属性值数组     foreach ($propertyValue as $proKey => &$proValue) {         // 如果属性值是注入对象,且是援用类型         if ($proValue instanceof ArgsInjection && $proValue->isRef()) {             // 获取援用的值             $refValue = $proValue->getValue();             // 将援用的值解析为实在的bean对象并替换原数组中的值             $proValue = $this->getRefValue($refValue, $id);         }     }     // 返回被替换后的值数组     return $propertyValue;}

通过援用获取实在bean对象的办法:

private function getRefValue($value, string $id = '') {      // 如果援用不是一个字符串,则间接返回该值     if (!is_string($value)) {        return $value;     }     // 如果值的第一个字符不是.(.这个字符是配置的应用形式)     // 则调用safeNewBean去获取或创立     // 实在的bean对象     if (strpos($value, '.') !== 0) {        return $this->safeNewBean($value, $id);     }          // 移除第一个.字符     // Remove `.`     $value = substr($value, 1);     // Other: read config reference     if ($this->handler) {        // 调用BeanHandler的getReferenceValue办法获取值        // 实际上就是去Config的bean对象中获取配置信息        $value = $this->handler->getReferenceValue($value);     }     return $value; }

平安获取bean办法:

private function safeNewBean(string $beanName, string $id = ''){     try {        // 调用newBean获取或创立bean        // 这里就呈现了递归        // 如果两个bean对象互相援用,此处就会导致死循环        return $this->newBean($beanName, $id);     } catch (Throwable $e) {        throw new InvalidArgumentException($e->getMessage(), 500, $e);     }}

总结:

初始化流程:    1.遍历定义对象数组.    2.如果定义对象是request或者session类型,则转存定义对象到对应数组中保留.    3.如果是singleton或者prototype类型,则依据定义对象创立真正的bean对象,保留在容器对应的对象池中.创立bean对象的流程:    1.查看bean是否曾经存在于对应的对象池,如果存在则不再创立.    2.获取要创立的bean对象的定义对象.    3.依据定义对象中设置的类名创立反射类对象,并将该反射类对象缓存起来.    4.调用bean生命周期--初始化前回调.    5.从定义对象获取结构注入对象,再从结构注入对象中获取须要注入的结构参数.    6.查看以后要创立的bean对象的类是否有代理类,如果有,则将先前创立的类反射对象替换成代理类的类反射对象.    7.通过类反射对象和结构参数,创立该类的实例对象(这就是咱们最终须要的bean对象).    8.通过定义对象获取属性注入对象数组.    9.依据将属性注入对象中的值类型,以不同形式将值赋值给实例对象.        9.1.递归遍历反射类及其所有父类.        9.2.顺次遍历属性注入对象数组,找到匹配的属性.        9.3.判断值的类型,如果是一般类型,则间接进入赋值流程.        9.4.如果是援用类型(或数组中蕴含援用类型),则调用获取援用值的办法,获取(递归,如果这个bean对象不存在则持续调用bean对象生成办法)援用值对应的bean对象.    10.保留别名和bean名称的映射.    11.如果反射类有init办法,则调用反射实例的init办法.    12.将最终的反射实例保留在对应的对象池中,并按类型返回一个对应的对象,此处保留的反射实例就是咱们最终生成的bean对象.当然,还有一些干线细节,此大节中没有讲到的,可能后续回再做补充.比方创立bean对象流程中的:    1.第6步中波及的代理类.    2.……

至此,bean处理器的工作曾经实现.当初,咱们曾经能够在业务中应用bean了.