1反射原理的梳理
1.1 BeanFactory属性注解
seckill\pro\core\BeanFactory.php
private static function handlerPropAnno(&$instance,\ReflectionClass $refClass,AnnotationReader $reader) { //读取反射对象的属性 $props = $refClass->getProperties(); foreach ($props as $prop){ //$prop必须是反射对象属性 $propAnnos = $reader->getPropertyAnnotations($prop); foreach ($propAnnos as $propAnno){ //返回对象实例 obj 所属类的名字。如果 obj 不是一个对象则返回 FALSE $handler = self::$handlers[get_class($propAnno)]; $handler($prop,$instance,$propAnno); } } }
其中
第一个参数
//读取反射对象的属性
$props = $refClass->getProperties();
第二个参数
$instance = self::$container->get($refClass->getName())
第三个参数
//$prop必须是反射对象属性
$propAnnos = $reader->getPropertyAnnotations($prop);
DB类自身
1.2 handler
seckill\pro\core\annotationhandlers\DBHandler.php
return [ /** * @prop * object(ReflectionProperty)#48 (2) { ["name"]=> string(2) "db" ["class"]=> string(30) "App\controllers\UserController" } * @instance * object(App\controllers\UserController)#52 (2) { ["db":"App\controllers\UserController":private]=> NULL ["version"]=> string(3) "1.0" } * @self * object(Core\annotations\DB)#55 (1) { ["source"]=> string(6) "docker" } */ DB::class=>function(\ReflectionProperty $prop,$instance,$self) { $mydbBean = BeanFactory::getBean(MyDB::class); //从新获取一个对象 $mydbBean ->setDbSource($self->source);//annotations/DB 里设置的数据源 $prop->setAccessible(true); // $prop->setValue($instance,$mydbBean); return $instance; } ];
第一个参数\ReflectionProperty $prop $prop
来源于 \controllers\UserController.php
第二次参数 $instance
本来是指\controllers\UserController的实例
object(App\controllers\UserController)#52 (2) { ["db":"App\controllers\UserController":private]=> NULL ["version"]=> string(3) "1.0" }
经过 $prop->setValue($instance,$mydbBean);后
变成
object(App\controllers\UserController)#52 (2) { ["db":"App\controllers\UserController":private]=> object(Core\init\MyDB)#37 (2) { ["lvDB"]=> object(Illuminate\Database\Capsule\Manager)#38 (2) { ["manager":protected]=> object(Illuminate\Database\DatabaseManager)#45 (6) { ["app":protected]=> object(Illuminate\Container\Container)#42 (19) { ["resolved":protected]=> array(0) { } ["bindings":protected]=> array(0) { } ["methodBindings":protected]=> array(0) { } ["instances":protected]=> array(1) { ["config"]=> object(Illuminate\Support\Fluent)#43 (1) { ["attributes":protected]=> array(3) { ["database.fetch"]=> int(5) ["database.default"]=> string(7) "default" ["database.connections"]=> array(2) { ["default"]=> array(9) { ["driver"]=> string(5) "mysql" ["host"]=> string(12) "10.10.10.114" ["port"]=> string(4) "3306" ["database"]=> string(4) "test" ["username"]=> string(3) "ttt" ["password"]=> string(6) "123456" ["charset"]=> string(7) "utf8mb4" ["collation"]=> string(18) "utf8mb4_general_ci" ["prefix"]=> string(0) "" } ["docker"]=> array(9) { ["driver"]=> string(5) "mysql" ["host"]=> string(12) "10.10.10.234" ["port"]=> string(5) "12345" ["database"]=> string(7) "seckill" ["username"]=> string(4) "root" ["password"]=> string(6) "123456" ["charset"]=> string(7) "utf8mb4" ["collation"]=> string(18) "utf8mb4_general_ci" ["prefix"]=> string(0) "" } } } } } ["scopedInstances":protected]=> array(0) { } ["aliases":protected]=> array(0) { } ["abstractAliases":protected]=> array(0) { } ["extenders":protected]=> array(0) { } ["tags":protected]=> array(0) { } ["buildStack":protected]=> array(0) { } ["with":protected]=> array(0) { } ["contextual"]=> array(0) { } ["reboundCallbacks":protected]=> array(0) { } ["globalBeforeResolvingCallbacks":protected]=> array(0) { } ["globalResolvingCallbacks":protected]=> array(0) { } ["globalAfterResolvingCallbacks":protected]=> array(0) { } ["beforeResolvingCallbacks":protected]=> array(0) { } ["resolvingCallbacks":protected]=> array(0) { } ["afterResolvingCallbacks":protected]=> array(0) { } } ["factory":protected]=> object(Illuminate\Database\Connectors\ConnectionFactory)#44 (1) { ["container":protected]=> object(Illuminate\Container\Container)#42 (19) { ["resolved":protected]=> array(0) { } ["bindings":protected]=> array(0) { } ["methodBindings":protected]=> array(0) { } ["instances":protected]=> array(1) { ["config"]=> object(Illuminate\Support\Fluent)#43 (1) { ["attributes":protected]=> array(3) { ["database.fetch"]=> int(5) ["database.default"]=> string(7) "default" ["database.connections"]=> array(2) { ["default"]=> array(9) { ["driver"]=> string(5) "mysql" ["host"]=> string(12) "10.10.10.114" ["port"]=> string(4) "3306" ["database"]=> string(4) "test" ["username"]=> string(3) "ttt" ["password"]=> string(6) "123456" ["charset"]=> string(7) "utf8mb4" ["collation"]=> string(18) "utf8mb4_general_ci" ["prefix"]=> string(0) "" } ["docker"]=> array(9) { ["driver"]=> string(5) "mysql" ["host"]=> string(12) "10.10.10.234" ["port"]=> string(5) "12345" ["database"]=> string(7) "seckill" ["username"]=> string(4) "root" ["password"]=> string(6) "123456" ["charset"]=> string(7) "utf8mb4" ["collation"]=> string(18) "utf8mb4_general_ci" ["prefix"]=> string(0) "" } } } } } ["scopedInstances":protected]=> array(0) { } ["aliases":protected]=> array(0) { } ["abstractAliases":protected]=> array(0) { } ["extenders":protected]=> array(0) { } ["tags":protected]=> array(0) { } ["buildStack":protected]=> array(0) { } ["with":protected]=> array(0) { } ["contextual"]=> array(0) { } ["reboundCallbacks":protected]=> array(0) { } ["globalBeforeResolvingCallbacks":protected]=> array(0) { } ["globalResolvingCallbacks":protected]=> array(0) { } ["globalAfterResolvingCallbacks":protected]=> array(0) { } ["beforeResolvingCallbacks":protected]=> array(0) { } ["resolvingCallbacks":protected]=> array(0) { } ["afterResolvingCallbacks":protected]=> array(0) { } } } ["connections":protected]=> array(0) { } ["extensions":protected]=> array(0) { } ["reconnector":protected]=> object(Closure)#46 (2) { ["this"]=> *RECURSION* ["parameter"]=> array(1) { ["$connection"]=> string(10) "<required>" } } ["doctrineTypes":protected]=> array(0) { } } ["container":protected]=> object(Illuminate\Container\Container)#42 (19) { ["resolved":protected]=> array(0) { } ["bindings":protected]=> array(0) { } ["methodBindings":protected]=> array(0) { } ["instances":protected]=> array(1) { ["config"]=> object(Illuminate\Support\Fluent)#43 (1) { ["attributes":protected]=> array(3) { ["database.fetch"]=> int(5) ["database.default"]=> string(7) "default" ["database.connections"]=> array(2) { ["default"]=> array(9) { ["driver"]=> string(5) "mysql" ["host"]=> string(12) "10.10.10.114" ["port"]=> string(4) "3306" ["database"]=> string(4) "test" ["username"]=> string(3) "ttt" ["password"]=> string(6) "123456" ["charset"]=> string(7) "utf8mb4" ["collation"]=> string(18) "utf8mb4_general_ci" ["prefix"]=> string(0) "" } ["docker"]=> array(9) { ["driver"]=> string(5) "mysql" ["host"]=> string(12) "10.10.10.234" ["port"]=> string(5) "12345" ["database"]=> string(7) "seckill" ["username"]=> string(4) "root" ["password"]=> string(6) "123456" ["charset"]=> string(7) "utf8mb4" ["collation"]=> string(18) "utf8mb4_general_ci" ["prefix"]=> string(0) "" } } } } } ["scopedInstances":protected]=> array(0) { } ["aliases":protected]=> array(0) { } ["abstractAliases":protected]=> array(0) { } ["extenders":protected]=> array(0) { } ["tags":protected]=> array(0) { } ["buildStack":protected]=> array(0) { } ["with":protected]=> array(0) { } ["contextual"]=> array(0) { } ["reboundCallbacks":protected]=> array(0) { } ["globalBeforeResolvingCallbacks":protected]=> array(0) { } ["globalResolvingCallbacks":protected]=> array(0) { } ["globalAfterResolvingCallbacks":protected]=> array(0) { } ["beforeResolvingCallbacks":protected]=> array(0) { } ["resolvingCallbacks":protected]=> array(0) { } ["afterResolvingCallbacks":protected]=> array(0) { } } } ["dbSource":"Core\init\MyDB":private]=> string(6) "docker" } ["version"]=> string(3) "1.0" }
第三个参数 $self
seckill\pro\core\annotations\DB.php的实例
2 我现在的注解类型
2.1 @Bean 实例化后加载在IOC容器中
//Spring的@Bean注解用于告诉方法,产生一个Bean对象,然后这个Bean对象交给Spring管理。产生这个Bean对象的方法Spring只会调用一次,随后这个Spring将会将这个Bean对象放在自己的IOC容器中;
/** * @Bean * @method \Illuminate\Database\Query\Builder table(string $table,string|null $as=null,string|null $connection=null) * @method \Illuminate\Database\Query\Builder connection(string|null $connection=null) */ class MyDB
2.2 @DB 数据库资源注解
/** * @DB * @var MyDB */ private $db;
2.3 @Model 数据模型注解(尚未完成)
2.4 @RequestMapping 路由注解
/** * @RequestMapping(value="/test") */ public function test(Response $response )
2.5 @Value 属性注解
/** * @Value(name="version") * @var string */ public $version = '1.0';
3 多数据源的切换
3.1 使用方法
seckill\pro\app\controllers\UserController.php
/** * @DB(source ="default") * @var MyDB */ private $db1; /** * @DB(source ="docker") * @var MyDB */ private $db2; /** * @Value(name="version") * @var string */
3.2 实现
seckill\pro\core\annotationhandlers\DBHandler.php
DB::class=>function(\ReflectionProperty $prop,$instance,$self) { $mydbBean = BeanFactory::getBean(MyDB::class); //获取IOC容器的对象 $mydbBean ->setDbSource($self->source); if ($self->sourc!=='default'){ $newBeanName = MyDB::class."_".$self->source; $newBean = BeanFactory::getBean($newBeanName); if(!$newBean){ $newBean = clone $mydbBean ; $newBean ->setDbSource($self->source);//默认为annotations/DB 里设置的数据源 BeanFactory::setBean($newBeanName,$newBean); } $mydbBean = $newBean; } $prop->setAccessible(true); // //ReflectionProperty::setValue( object $object , mixed $value ) //$instance 如果该属性是非静态的,则必须提供一个对象以更改该属性。 如果属性是静态的,则忽略此参数,仅需要提供值。 //$mydbBean 新的属性值 //把lvDB装载到UserController的实例里 $prop->setValue($instance,$mydbBean); return $instance; }
seckill\pro\core\BeanFactory.php
public static function setBean($name,$value) { return self::$container->set($name,$value); }
4 完整代码
https://github.com/guainttt/seckill/commit/b1db22b9209473eeaa4d289643df1b26db79f851