laravel 服务容器实现原理

本文涉及的产品
容器镜像服务 ACR,镜像仓库100个 不限时长
简介:

前言

通过实现laravel 框架功能,以便深入理解laravel框架的先进思想。

什么是服务容器

服务容器是用来管理类依赖与运行依赖注入的工具。Laravel框架中就是使用服务容器来实现 ** 控制反转 ** 和 ** 依赖注入 **。

什么是控制反转(IoC)和依赖注入(DI)

控制反转(IoC) 就是说把创建对象的** 控制权 进行转移,以前创建对象的主动权和创建时机是由自己把控的,而现在这种权力转移到第三方,也就是 Laravel ** 中的容器。

依赖注入(DI)则是帮助容器实现在运行中动态的为对象提供提依赖的资源。

概念容易不太容易让人理解,举个栗子:

//我们构建一个人的类和一个狗的类
 class People{    public $dog = null;    public function __construct()
    {
        $this->dog = new Dog();
    }    public function putDog(){        return $this->dog->dogCall();
    }

}class Dog{    public function dogCall(){        return '汪汪汪';
    }
}
 ``` 
这个人在遛狗,突然遇到了死对头,他于是放狗咬人

$people = new People();
$people->putDog();
在这个操作中,people类要执行 putDog() 这个方法,需要依赖Dog类,一般我们像上面一样,在people中利用构造函数来添加这个Dog依赖。如果使用控制反转 依赖注入则是这个样子
class People
{
public $dog = null;

public function __construct(Dog $Dog){
    $this->dog = $dog;
}public function putDog(){    return $this->dog->dogCall();
}

}

People类通过构造参数声明自己需要的 依赖类,由容器自动注入。这样就实现了程序的有效解耦,好处在这就不多说了。## Laravel容器依赖注入的实现###### 实现原理需要了解的知识点:> 闭包(匿名函数):匿名函数(Anonymous functions),也叫闭包函数(closures),允许 临时创建一个没有指定名称的函数> 反射:PHP 5 以上版本具有完整的反射 API,添加了对类、接口、函数、方法和扩展进行反向工程的能力。 此外,反射 API 提供了方法来取出函数、类和方法中的文档注释###### 理解了闭包和反射的基本用法我们来看Laravel中是怎么实现容器的,下面代码是我对laravel框架容器部分代码的简化核心版:

lass Container
{
/**
* 容器绑定,用来装提供的实例或者 提供实例的回调函数
* @var array
*/
public $building = [];

/**
 * 注册一个绑定到容器
 */public function bind($abstract, $concrete = null, $shared = false){    if(is_null($concrete)){
        $concrete = $abstract;
    }    if(!$concrete instanceOf Closure){
        $concrete = $this->getClosure($abstract, $concrete);
    }

    $this->building[$abstract] =  compact("concrete", "shared");
}//注册一个共享的绑定 单例public function singleton($abstract, $concrete, $shared = true){
    $this->bind($abstract, $concrete, $shared);
}/**
 * 默认生成实例的回调闭包
 *
 * @param $abstract
 * @param $concrete
 * @return Closure
 */public function getClosure($abstract, $concrete){    return function($c) use($abstract, $concrete){
        $method = ($abstract == $concrete)? 'build' : 'make';        return $c->$method($concrete);
    };
}/**
 * 生成实例 
 */public function make($abstract){
    $concrete = $this->getConcrete($abstract);    if($this->isBuildable($concrete, $abstract)){
        $object = $this->build($concrete);
    }else{
        $object = $this->make($concrete);
    }    return $object;
}/**
 * 获取绑定的回调函数
 */public function getConcrete($abstract){    if(! isset($this->building[$abstract])){        return $abstract;
    }    return $this->building[$abstract]['concrete'];
}/**
 * 判断 是否 可以创建服务实体
 */public function isBuildable($concrete, $abstract){    return $concrete === $abstract || $concrete instanceof Closure;
}/**
 * 根据实例具体名称实例具体对象
 */public function build($concrete){    if($concrete instanceof Closure){        return $concrete($this);
    }    //创建反射对象
    $reflector = new ReflectionClass($concrete);    if( ! $reflector->isInstantiable()){        //抛出异常
        throw new \Exception('无法实例化');
    }

    $constructor = $reflector->getConstructor();    if(is_null($constructor)){        return new $concrete;
    }

    $dependencies = $constructor->getParameters();
    $instance = $this->getDependencies($dependencies);    return $reflector->newInstanceArgs($instance);

}//通过反射解决参数依赖public function getDependencies(array $dependencies){
    $results = [];    foreach( $dependencies as $dependency ){
        $results[] = is_null($dependency->getClass())
            ?$this->resolvedNonClass($dependency)
            :$this->resolvedClass($dependency);
    }    return $results;
}//解决一个没有类型提示依赖public function resolvedNonClass(ReflectionParameter $parameter){    if($parameter->isDefaultValueAvailable()){        return $parameter->getDefaultValue();
    }    throw new \Exception('出错');

}//通过容器解决依赖public function resolvedClass(ReflectionParameter $parameter){    return $this->make($parameter->getClass()->name);

}

}
```

容器的工作流程

接着上面遛狗的例子:
//实例化容器类 $app = new Container(); //向容器中填充Dog $app->bind('Dog','App\Dog'); //填充People $app->bind('People', 'App\People'); //通过容器实现依赖注入,完成类的实例化; $people = $app->make('People'); //调用方法 echo $people->putDog();
上面示例中我们先实例化容器类,然后使用bind()方法 绑定接口和 生成相应的实例的闭包函数。然后使用make() 函数生成实例对象,在make()中会调用 isBuildable($concrete, $abstract) 来判断 给定的服务实体($concrete参数)是否可以创建,可以创建 就会调用 build($concrete) 函数 ,build($concrete)函数会判断传的参数是 是** 闭包 还是 具体类名 **,如果是闭包则直接运行,如果是具体类名的话,则通过反射获取该类的构造函数所需的依赖,完成实例化。

** 重点理解 下面这几个函数中 反射的用法,应该就很好理解了 **
build($concrete) getDependencies(array $dependencies) resolvedNonClass(ReflectionParameter $parameter) resolvedClass(ReflectionParameter $parameter)

本文转自  zddnd  51CTO博客,原文链接:http://blog.51cto.com/13013666/1943082
相关文章
|
2月前
|
Kubernetes Cloud Native Docker
云原生之旅:从传统架构到容器化服务的演变
随着技术的快速发展,云计算已经从简单的虚拟化服务演进到了更加灵活和高效的云原生时代。本文将带你了解云原生的概念、优势以及如何通过容器化技术实现应用的快速部署和扩展。我们将以一个简单的Python Web应用为例,展示如何利用Docker容器进行打包和部署,进而探索Kubernetes如何管理这些容器,确保服务的高可用性和弹性伸缩。
|
4月前
|
XML Java 开发者
经典面试---spring IOC容器的核心实现原理
作为一名拥有十年研发经验的工程师,对Spring框架尤其是其IOC(Inversion of Control,控制反转)容器的核心实现原理有着深入的理解。
186 3
|
5月前
|
弹性计算 Kubernetes 开发者
利用容器化服务实现游戏服务器的动态资源配置
【8月更文第12天】在游戏行业中,用户基数的变化往往呈现出明显的波动性,特别是在推广活动期间,用户基数会显著增加,而在非推广期则会有所下降。为了应对这种变化,游戏开发者需要一种能够根据用户基数动态调整服务器资源的解决方案,以确保用户体验的同时最大限度地节省成本。容器化服务因其灵活的资源管理和成本控制能力,成为了理想的解决方案。
84 2
|
6月前
|
运维 Kubernetes 开发者
构建高效后端服务:微服务架构与容器化部署的实践
【7月更文挑战第29天】 在现代软件开发中,后端服务的构建不再仅仅是代码的堆砌,而是需要考虑到可扩展性、可靠性和快速迭代等多重因素。本文将探讨如何通过微服务架构和容器化技术来构建一个高效的后端服务系统。我们将从微服务的概念出发,分析其在后端开发中的应用优势,并结合容器化技术,特别是Docker和Kubernetes的使用,来展示如何在保证服务高可用性和伸缩性的同时,简化开发和部署流程。文章还将涵盖如何应对微服务架构下的数据一致性挑战,以及如何利用现代云平台资源来优化后端服务的性能和成本效益。
|
6月前
|
Shell 应用服务中间件 nginx
docker 服务,镜像,容器命令总结
docker 服务,镜像,容器命令总结
190 4
|
5月前
|
Kubernetes 网络协议 网络安全
在K8S中,容器提供一个服务,外部访问慢,到底是容器网络问题?还是容器服务问题?这种怎么排查?
在K8S中,容器提供一个服务,外部访问慢,到底是容器网络问题?还是容器服务问题?这种怎么排查?
|
5月前
|
Kubernetes 负载均衡 网络协议
在K8S中,Pod能否实现对容器健康检查,如果服务有异常,该如何处理?
在K8S中,Pod能否实现对容器健康检查,如果服务有异常,该如何处理?
|
8月前
|
Kubernetes 负载均衡 开发者
构建高效后端服务:从微服务到容器化部署
【5月更文挑战第31天】本文深入探讨了现代后端开发中的关键概念,包括微服务的架构设计、容器化技术的运用以及它们如何共同提升应用的可扩展性、可靠性和性能。通过具体案例分析,我们将揭示这些技术是如何在实际开发中被实施的,并讨论它们对后端开发流程的影响。
|
1月前
|
监控 NoSQL 时序数据库
《docker高级篇(大厂进阶):7.Docker容器监控之CAdvisor+InfluxDB+Granfana》包括:原生命令、是什么、compose容器编排,一套带走
《docker高级篇(大厂进阶):7.Docker容器监控之CAdvisor+InfluxDB+Granfana》包括:原生命令、是什么、compose容器编排,一套带走
271 77
|
17天前
|
Ubuntu NoSQL Linux
《docker基础篇:3.Docker常用命令》包括帮助启动类命令、镜像命令、有镜像才能创建容器,这是根本前提(下载一个CentOS或者ubuntu镜像演示)、容器命令、小总结
《docker基础篇:3.Docker常用命令》包括帮助启动类命令、镜像命令、有镜像才能创建容器,这是根本前提(下载一个CentOS或者ubuntu镜像演示)、容器命令、小总结
102 6
《docker基础篇:3.Docker常用命令》包括帮助启动类命令、镜像命令、有镜像才能创建容器,这是根本前提(下载一个CentOS或者ubuntu镜像演示)、容器命令、小总结