简介
服务提供者,见名知意,就是提供服务的地方。我们再回顾一下上一篇《Laravel初级教程之服务容器》,在这篇文章中说到,服务容器是“盛放”服务的地方,那我们通过什么地方把我们开发好的服务放到服务容器呢?而服务提供者就是我们将服务放到服务容器的地方。更官方的一点说法就是:
服务提供者是
Laravel
应用启动的中心,你自己的应用以及所有Laravel
的核心服务都是通过服务提供者启动。当然启动这些服务,需要加载注册服务,包括注册服务容器绑定、事件监听器、中间件甚至路由。服务提供者是应用配置的中心。
各位读者看看,服务提供者是应用配置的中心。这样你就应该知道服务提供者的作用和地位了吧。对于这样重要的一部分,接下来,我会循序渐进,通过代码示例,给大家总结如何完成一个完整的服务提供者的开发,最后会通过一个完整的短信发送的实例,来完成服务容器和服务提供者的实战演练。
为了方便配合下面内容的展开,我这里需要先定义一个接口,以及对应的实现。
接口定义:
<?php
namespace App\Service\interfaces;
interface ISMS
{
function sendSMS($phoneNum, $smsContent);
}
对应接口实现类:
<?php
namespace App\Service\impl;
use App\Service\interfaces\ISMS;
use Yunpian\Sdk\YunpianClient;
class YunPianSMS implements ISMS
{
function sendSMS($phoneNum, $smsContent) {
//初始化client,apikey作为所有请求的默认值
$clnt = YunpianClient::create(env("YUNPIAN_API_KEY"));
$param = [YunpianClient::MOBILE => $phoneNum,YunpianClient::TEXT => $smsContent];
$r = $clnt->sms()->single_send($param);
if($r->isSucc()) {
$r->data();
}
}
}
开发服务提供者
所有的服务提供者都继承自Illuminate\Support\ServiceProvider
类。这个抽象类要求提供者必须最少定义一个register
方法。在register
方法中应该只绑定内容到服务容器。永远不要尝试在其中注册任何的事件监听,路由或者其它功能。因为我们可能使用了还未注册的服务,从而导致异常。
我们可以通过make:provider
命令来非常便捷的生成一个新的服务提供者:
php artisan make:provider SMSServiceProvider
执行成功后,便在app/Providers
目录下生成一个SMSServiceProvider.php文件,生成的模板内容如下:
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class SMSServiceProvider extends ServiceProvider
{
/**
* Bootstrap services.
*
* @return void
*/
public function boot()
{
//
}
/**
* Register services.
*
* @return void
*/
public function register()
{
//
}
}
可以看到,生成的服务提供者模板中就只有两个方法:boot
和register
。而我们在开发服务提供者时,也都是在这两个方法中“搞事情”;也就是说,搞明白在boot
方法中该写点什么,又或在register
方法中写点什么,这样就就掌握了如何开发服务提供者。下面对这两个方法分别进行详细的总结。
boot
方法
对于boot
方法,需要记住以下一点:boot
方法在所有服务提供者被注册以后才会被调用,这就是说我们可以在其中访问框架已注册的所有其它服务。boot
方法在register
方法之后调用,这就意味着,我们无须担心在注入某个实例的时候,它还没有被绑定或实例化。在实际工作中,
boot
中一般完成启动相应的服务的工作。-
register
方法
对于register
方法,需要记住以下一点:在
register
方法中只绑定服务到服务容器,而不要做其它事情。
根据上面对boot
和register
两个方法的认识,接下来我们来完成这个SMSServiceProvider
。
public function register()
{
$this->app->singleton("SMSService", function($app) {
return new YunPianSMS();
});
}
注册服务提供者
服务提供者多了,系统难免难于管理,为了更有条理的管理好各类服务提供者,所有的服务提供者都被注册在config/app.php
配置文件中。这个文件包含了providers
数组,这数组列出了所有服务提供者的名字。默认的,laravel中的核心服务都被注册在这个数组里。这些提供者启动了laravel中的核心组件,如邮件,队列,缓存和其他。
现在我们可以在该数组中进行添加注册服务提供者:
'providers' => [
// Other Service Providers
App\Providers\SMSServiceProvider::class
],
延迟加载
如果我们的服务提供者中提供的服务,并不会被每次请求都用到,或者很少用到。那么我们可以选择推迟注册。这样这些服务只有在真正被需要用到时才会进行注册。推迟注册能够提高应用的性能,因为它不会在所有请求到来时都通过文件系统来加载。
为了推迟服务提供者的加载,我们可以在提供者类中设置defer
属性为true
,并且定义一个provides
方法。provides
方法会返回服务提供者注册的服务容器的绑定,最终,我们的服务提供者应该似乎这个样子:
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use App\Service\impl\YunPianSMS;
class SMSServiceProvider extends ServiceProvider
{
/**
* 服务提供者加是否延迟加载.
*
* @var bool
*/
protected $defer = true;
/**
* Bootstrap services.
*
* @return void
*/
public function boot()
{
//
}
/**
* Register services.
*
* @return void
*/
public function register()
{
$this->app->singleton("SMSService", function($app) {
return new YunPianSMS();
});
}
/**
* 获取由提供者提供的服务.
*
* @return array
*/
public function provides()
{
return ['SMSService'];
}
}
实战演练
写到这里,如果你亲自把文中的代码都敲了一遍,你会发现这就是一个短信下发的Demo,去云片网申请一个测试账号,即可完成这篇文章的短信下发功能了。
Route::get('/sendSMS', function() {
$smsService = resolve('SMSService');
$phoneNum = '1503497XXX';
$smsContent = '【果冻想】认真玩技术的地方。';
$smsService->sendSMS($phoneNum, $smsContent);
});
总结
断断续续,花费了将近3天的时间,把这篇文章总结完成。由于服务提供者的作用太重要了,导致自己在总结时也是不敢有一丝懈怠,阅读了多篇文章后,才敢动手开始总结。每总结一篇文章,都是对自己的一次提高;也是自己对知识点理解的一次升华。透彻的理解每个知识点,在后续的填坑生涯中,将会得心应手。
果冻想,认真玩技术的地方。
2018年3月31日 于内蒙古呼和浩特。
非常详细。谢谢!
写得非常不错!
谢谢~~~