laravel 服务提供者
服务提供者,在laravel里面,其实就是一个工厂类。它最大的作用就是用来进行服务绑定。当我们需要绑定一个或多个服务的时候,可以自定义一个服务提供者,然后把服务绑定的逻辑都放在该类的实现中。在larave里面,要自定一个服务提供者非常容易,只要继承Illuminate\Support\ServiceProvider这个类即可。下面通过一个简单的自定义服务提供者来说明服务提供者的一些要点:
<?php namespace App\Providers; use Illuminate\Support\ServiceProvider; class AppServiceProvider extends ServiceProvider
{
protected $defer = true; public function boot()
{
//
} public function register()
{
$this->app->singleton('service1', function(){
return 'service1';
});
$this->app->singleton('service2', function(){
return 'service2';
});
$this->app->singleton('service3', function(){
return 'service3';
});
} public function provides()
{
return ['service1','service2','service3'];
}
}
1). 首先,自定义的服务提供者都是放在下面这个目录的:

其实你放在哪都可以,不过得告诉laravel你的服务提供者在哪,laravel才会帮你注册。怎么告诉它,后面还有介绍。
2)在这个举例里面,可以看到有一个register方法,这个方法是ServiceProvider里面定义的。自定义的时候,需要重写它。这个方法就是用来绑定服务的。你可以在这个服务里面,根据需要加入任意数量的服务绑定。前面要介绍过,在服务提供者里面,始终能通过$this->app拿到容器实例,所以上面的举例中,我们直接用这种方式来完成服务绑定。这个方法是怎么完成服务绑定的呢?因为当laravel找到这个服务提供者的类以后,就会初始化这个服务提供者类,得到一个服务提供者的对象,然后调用它的register方法,自然它里面的所有服务绑定代码就都会执行了。
laravel初始化自定义服务提供者的源码是:
public function registerConfiguredProviders()
{
$manifestPath = $this->getCachedServicesPath(); (new ProviderRepository($this, new Filesystem, $manifestPath))
->load($this->config['app.providers']);
}
这个代码是在Illuminate\Foundation\Application的源码里面拿出来的,从中你能看到laravel会把所有的自定义服务提供者都注册进来。这个注册的过程其实就是前面说的实例化服务提供者的类,并调用register方法的过程。
3). 从上一步的源码也能看到,laravel加载自定义服务提供者的时候,实际是从config/app.php这个配置文件里面的providers配置节找到所有要注册的服务提供者的。
'providers' => [
/*
* Laravel Framework Service Providers...
*/
Illuminate\Auth\AuthServiceProvider::class,
Illuminate\Broadcasting\BroadcastServiceProvider::class,
Illuminate\Bus\BusServiceProvider::class,
Illuminate\Cache\CacheServiceProvider::class,
Illuminate\Foundation\Providers\ConsoleSupportServiceProvider::class,
Illuminate\Cookie\CookieServiceProvider::class,
Illuminate\Database\DatabaseServiceProvider::class,
Illuminate\Encryption\EncryptionServiceProvider::class,
Illuminate\Filesystem\FilesystemServiceProvider::class,
Illuminate\Foundation\Providers\FoundationServiceProvider::class,
Illuminate\Hashing\HashServiceProvider::class,
Illuminate\Mail\MailServiceProvider::class,
Illuminate\Notifications\NotificationServiceProvider::class,
Illuminate\Pagination\PaginationServiceProvider::class,
Illuminate\Pipeline\PipelineServiceProvider::class,
Illuminate\Queue\QueueServiceProvider::class,
Illuminate\Redis\RedisServiceProvider::class,
Illuminate\Auth\Passwords\PasswordResetServiceProvider::class,
Illuminate\Session\SessionServiceProvider::class,
Illuminate\Translation\TranslationServiceProvider::class,
Illuminate\Validation\ValidationServiceProvider::class,
Illuminate\View\ViewServiceProvider::class,
/*
* Package Service Providers...
*/
//
/*
* Application Service Providers...
*/
App\Providers\AppServiceProvider::class,
App\Providers\AuthServiceProvider::class,
// App\Providers\BroadcastServiceProvider::class,
App\Providers\EventServiceProvider::class,
App\Providers\RouteServiceProvider::class,
Xavrsl\Cas\CasServiceProvider::class,
ThirdProviders\CasServer\CasServerProvider::class
],
所以你如果自己写了一个服务提供者,那么只要配置到这里面,laravel就会自动帮你注册它了。
4)除了register方法,服务提供者里面还有一个boot方法,这个boot方法,会在所有的服务提供者都注册完成之后才会执行,所以当你想在服务绑定完成之后,通过容器解析出其它服务,做一些初始化工作的时候,那么就可以这些逻辑写在boot方法里面。因为boot方法执行的时候,所有服务提供者都已经被注册完毕了,所以在boot方法里面能够确保其它服务都能被解析出来。
5)前面说的服务提供者的情况,在laravel应用程序初始化的时候,就会去注册服务提供者,调用register方法。但是还有一种需求,你可能需要在真正用到这个服务提供者绑定的服务的时候,才会去注册这个服务提供者,以减少不必要的注册处理,提高性能。这也是延迟处理的一种方式。那么这种服务提供者该怎么定义呢?
其实最前面的这个举例已经告诉你了,只要定义一个$defer的实例属性,并把这个实例属性设置为true,然后添加一个provides的实例方法即可。这两个成员都是ServiceProvider基类里面定义好的,自定义的时候,只是覆盖而已。
在基类中,$defer的默认值是false,表示这个服务提供者不需要延迟注册。provides方法,只要简单的返回这个服务提供register方法里面,注册的所有服务绑定名称即可。
延迟注册的服务提供者的机制是:
- 当laravel初始化服务提供者的实例后,如果发现这个服务提供者的$defer属性为true,那么就不会去调用它的register方法
- 当laravel解析一个服务的时候,如果发现这个服务是由一个延迟服务提供的(它怎么知道这个服务是延迟服务提供的,是provides方法告诉它的),那么就会先把这个延迟服务提供者先注册,再去解析。这个可以看看Illuminate\Foundation\Application的make方法就清楚了:
public function make($abstract, array $parameters = [])
{
$abstract = $this->getAlias($abstract); if (isset($this->deferredServices[$abstract])) {
$this->loadDeferredProvider($abstract);
} return parent::make($abstract, $parameters);
}
6)还记得容器实例结构上几个带有providers名称的属性数组吧:

在了解以上provider的机制后,这几个数组的作用也就比较清晰了。其中serviceProviders用来存放所有已经注册完毕的服务提供者:

loadedProviders跟serviceProviders的作用类似,只是存储的记录形式不同:

deferredProviders用来存储所有的延迟注册的服务提供者:

跟前面两个不同的是,deferredProviders存储的记录的key值并不是服务提供者的类型名称,而是服务提供者的provides返回数组里面的名称。并且如果一个服务提供者的provides里面返回了多个服务绑定名称的话,那么deferredProviders里面就会存多条记录:

这样是方便根据服务绑定名称,找到对应的服务提供者,并完成注册。当服务的解析的时候,会先完成延迟类型的服务提供者的注册,注册完毕,这个服务绑定名称在deferredProviders对应的那条记录就会删除掉。不过如果一个服务提供者provides了多个服务绑定名称,解析其中一个服务的时候,只移除该名称对应的deferredProviders记录,而不是所有。
7)服务提供者还有一个小问题值的注意,由于php是一门基本语言,在处理请求的时候,都会从入口文件把所有php都执行一遍。为了性能考虑,laravel会在第一次初始化的时候,把所有的服务提供者都缓存到bootstrap/cache/services.php文件里面,所以有时候当你改了一个服务提供者的代码以后,再刷新不一定能看到期望的效果,这有可能就是因为缓存所致。这时把services.php删掉就能看到你要的效果了。
laravel 服务提供者的更多相关文章
- Laravel 服务提供者实例教程 —— 创建 Service Provider 测试实例
从某种意义上说,服务提供者有点类似HTTP控制器,HTTP控制器用于为相关路由注册提供统一管理,而服务提供者用于为相关服务容器提供统一绑定场所,此外服务提供者还可以做一些初始化启动操作.Laravel ...
- laravel 服务提供者介绍和使用
#安装传送门 安装composer,以及通过composer安装laravel #讲解使用 服务提供者这个具体表现都是围绕着依赖注入 在根目录config/app.php的providers中的数组中 ...
- laravel服务提供者类说明
IoC 是将内部设计的类交给系统去控制,但是有些类在初始化的时候,需要制定特定的参数,或者当你需要将实现类绑定到某个接口,这时候就必须对这些依赖进行配置,系统才能正确解析并引用. register 而 ...
- Laravel服务/服务提供者/容器/契约和门面
1.服务是什么? 服务是提供了一些功能的类,比如发送邮件,写日志. 2.Laravel服务提供者是什么? 服务提供者中指明了这个提供者可以提供哪些服务(注册服务),以及服务注册后默认调用一些方法(bo ...
- 谈一谈 Laravel 5.5 的 「自动发现」和此刻心情
看了Taylor Otwell发表的Package Auto-Discovery In Laravel 5.5第一反应是 为啥... 也怪我,在开发之前忘记看5.5的开发代码动态,之前的文章中也提到过 ...
- 聊聊 Laravel 5.5 的 「自动发现」
ThinkSNS是什么? ThinkSNS(简称TS),一款全平台综合性社交系统,目前最新版本为ThinkSNS+.ThinkSNS V4 ThinkSNS[简]. 看了Taylor Otwell发表 ...
- laravel框架总结(五) -- 服务提供者(提及契约Contracts)
首先理解两个概念 1.契约:一组定义了框架核心服务的接口 2.服务提供者:所有 Laravel 应用程序启动的中心所在. 包括你自己的应用程序,以及所有的 Laravel 核心服务,都是通过服务提供者 ...
- laravel门面和服务提供者使用
关于laravel门面和服务提供者使用的一点见解,门面之词,不足之处,还请多多指教. 在laravel中,我们可能需要用到自己添加的类时,可以建立一个文件夹专门存放类文件,也可以使用laravel ...
- 简单理解laravel框架中的服务容器,服务提供者以及怎样调用服务
laravel被称为最优雅的框架,最近正在学习中,对于用惯了thinkphp.ci框架的人来说,服务容器.服务提供者,依赖注入这些概念简直是一脸懵逼.我花了些时间梳理了一下,也不敢确定自己说的是对 ...
随机推荐
- webwork框架
以前都没有用过WebWork这个框架,只是听说过.没想到现在要用,所以就自学了一下.做了个小例子给大家分享下中间遇到的苦难和经验. 准备工作:首先要去下载WebWork框架的开发包.我用的2.2.6版 ...
- 高德地图 location字段控制台显示 为字符串类型 实际为对象
help大神求指导 ? 高德地图new amap.PoiManager() 的 autoComplete方法 location字段控制台显示 为字符串类型 实际为对象 debugger过程入下图:
- ng directive compile pre-link post-link
原文链接: http://www.jb51.net/article/58229.htm 1.ng在link之前编译所有的指令,然后link又分为 pre-link 与 post-link阶段compi ...
- 【转】Python数据类型之“文本序列(Text Sequence)”
[转]Python数据类型之“文本序列(Text Sequence)” Python中的文本序列类型 Python中的文本数据由str对象或字符串进行处理. 1.字符串 字符串是Unicode码值的不 ...
- node promise库bluebird
var fs = require('fs') var Promise = require("bluebird") function file1() { return new Pro ...
- requests库入门09-OAUTH认证
实际登陆中,认证用到的token会变的,不过可以在GIthub设置一个私人token. 如图,登录GIthub,然后用户下面选择Settings/Developer settings/Personal ...
- u3d 2D开发学习
http://gad.qq.com/article/detail/45365 https://blog.csdn.net/s556699/article/details/55224830 UI层设计 ...
- Flash芯片你都认识吗?
[导读]Flash存储器,简称Flash,它结合了ROM和RAM的长处,不仅具备电子可擦除可编程的性能,还不会因断电而丢失数据,具有快速读取数据的特点;在现在琳琅满目的电子市场上,Flash总类可谓繁 ...
- 题解-bzoj4221 JOI2012kangaroo
Problem bzoj 题意:给定\(n\)只袋鼠,每只袋鼠有俩属性\(a,b\),若\(a_i\leq b_j\),则\(i\)是可以被\(j\)放置在袋子里的,求经过一系列放置操作后无法进行操作 ...
- ubuntu 安装 库文件
ubuntu 16.4 安装freeradius 时,缺少库文件 libtalloc, 使用命令: sudo apt-get install libtalloc 发现找不到库文件 libtallo ...