服务提供者,在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 服务提供者的更多相关文章

  1. Laravel 服务提供者实例教程 —— 创建 Service Provider 测试实例

    从某种意义上说,服务提供者有点类似HTTP控制器,HTTP控制器用于为相关路由注册提供统一管理,而服务提供者用于为相关服务容器提供统一绑定场所,此外服务提供者还可以做一些初始化启动操作.Laravel ...

  2. laravel 服务提供者介绍和使用

    #安装传送门 安装composer,以及通过composer安装laravel #讲解使用 服务提供者这个具体表现都是围绕着依赖注入 在根目录config/app.php的providers中的数组中 ...

  3. laravel服务提供者类说明

    IoC 是将内部设计的类交给系统去控制,但是有些类在初始化的时候,需要制定特定的参数,或者当你需要将实现类绑定到某个接口,这时候就必须对这些依赖进行配置,系统才能正确解析并引用. register 而 ...

  4. Laravel服务/服务提供者/容器/契约和门面

    1.服务是什么? 服务是提供了一些功能的类,比如发送邮件,写日志. 2.Laravel服务提供者是什么? 服务提供者中指明了这个提供者可以提供哪些服务(注册服务),以及服务注册后默认调用一些方法(bo ...

  5. 谈一谈 Laravel 5.5 的 「自动发现」和此刻心情

    看了Taylor Otwell发表的Package Auto-Discovery In Laravel 5.5第一反应是 为啥... 也怪我,在开发之前忘记看5.5的开发代码动态,之前的文章中也提到过 ...

  6. 聊聊 Laravel 5.5 的 「自动发现」

    ThinkSNS是什么? ThinkSNS(简称TS),一款全平台综合性社交系统,目前最新版本为ThinkSNS+.ThinkSNS V4 ThinkSNS[简]. 看了Taylor Otwell发表 ...

  7. laravel框架总结(五) -- 服务提供者(提及契约Contracts)

    首先理解两个概念 1.契约:一组定义了框架核心服务的接口 2.服务提供者:所有 Laravel 应用程序启动的中心所在. 包括你自己的应用程序,以及所有的 Laravel 核心服务,都是通过服务提供者 ...

  8. laravel门面和服务提供者使用

      关于laravel门面和服务提供者使用的一点见解,门面之词,不足之处,还请多多指教. 在laravel中,我们可能需要用到自己添加的类时,可以建立一个文件夹专门存放类文件,也可以使用laravel ...

  9. 简单理解laravel框架中的服务容器,服务提供者以及怎样调用服务

      laravel被称为最优雅的框架,最近正在学习中,对于用惯了thinkphp.ci框架的人来说,服务容器.服务提供者,依赖注入这些概念简直是一脸懵逼.我花了些时间梳理了一下,也不敢确定自己说的是对 ...

随机推荐

  1. python 的基础 学习 11天 作业题

    1.整理函数相关知识点,写博客 2.写函数,检查获取传入列表或元组对象的所有奇数位索引对应的元素,并将其作为新列表返回给调用者. def func1(argv): li = [] for i in r ...

  2. A - Piece of Cake Kattis - pieceofcake (数学)

    题目链接: A - Piece of Cake Kattis - pieceofcake 题目大意:给你一个多边形,然后给你这个多边形的每个点的坐标,让你从这个n个点中选出k个点,问这个k个点形成的面 ...

  3. scrapy基本使用(一)

    scrapy基本使用(一) 参考文档:Scrapy入门教程 http://scrapy-chs.readthedocs.io/zh_CN/0.24/intro/tutorial.html scrapy ...

  4. XLMHttpRequest对象的status属性,readyState属性以及onreadystatechange事件

    注:XLMHttpRequest简写为XHR 一.HTTP请求过程 (1)建立TCP链接 (2)web浏览器向web服务器发送请求命令 (3)web浏览器发送请求头信息 (4)web服务器应答 (5) ...

  5. yum upgrade卡在 清理initial-setup-0.3.9.30-1.el7.centos.x86_64

    我安装CENTOS7.2,用yum -y update进行更新 卡在这里了 清理 : initial-setup-0.3.9.30-1.el7.cent 目测是一个系统bug,执行关闭命令解决: sy ...

  6. android页面渲染速度提升的常用方法

    参考文档:http://blog.csdn.net/vector_yi/article/details/24402101 当activity中用到的布局较多较为复杂时,页面渲染就会变得复杂,现汇总以下 ...

  7. Spring Resource配置

    1-classpath的设置: 2-Resource类型 3-ResourceLoader接口 加载resource的接口,只有一个方法getResource().所有ApplicationConte ...

  8. Des加密解密算法java实现

    package tech.fullink.eaglehorn.utils; import javax.crypto.Cipher; import javax.crypto.SecretKey; imp ...

  9. dubbo源码分析14——DubboProtocol的export方法分析

    走到了这一步也挺不容易的,把之前的暴露入口代码再列出来回顾一下: //配置为none不暴露 if (! Constants.SCOPE_NONE.toString().equalsIgnoreCase ...

  10. Mysql 5.* 数据库备份及导入

    作者:邓聪聪 倒出数据文件 1) 导出数据和表结构: 进入数据库查看表结构 msql -u用户名 -p密码 msql -u用户名 -p密码 -S /var/lib/mysql/mysql.sock  ...