Laravel Service Provider 概念详解
Posted wgchen~
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Laravel Service Provider 概念详解相关的知识,希望对你有一定的参考价值。
目录阅读
- Laravel Service Provider 概念详解
- 概览
- 过程分析
- 1、首先,生成核心 Container : $app (实例化过程中还注册了一大堆基本的「绑定])
- 2、接下来注册 `Http\\Kernel , Console\\Kernel , Debug\\ExecptionHandler` 三个「单例」绑定:
- 3、然后「启动」应用
- 4、由于以前的「绑定」,`$kernel` 获取的其实是 `App\\Http\\Kernel` 类的实例,`App\\Http\\Kernel` 类又继承了 `Illuminate\\Foundation\\Http\\Kernel` 类。 其 `handle()` 方法执行了 `sendRequestThroughRouter()` 方法:
- 5、这个 `sendRequestThroughRouter()` 方法执行了一系列 `bootstrappers` (引导器)
- 6、`bootstrap()` 方法中又调用了 `Illuminate\\Foundation\\Application` 类的 `bootstrapWith() `方法
- 创建 Service Provier
Laravel Service Provider 概念详解
我们知道, Container
有很多种 「绑定」 的姿势,比如 bind() , extend() , singleton() , instance()
等等,那么 Laravel 中怎样「注册」这些「绑定」呢?
那就是 Service Provider
。
Service Providers
(服务提供者) 是 Laravel 「引导」过程的核心。
这个「引导」过程可以理解成「电脑从按下开机按钮到完全进入桌面」这段时间系统干的事。
概览
Service Provider
有两个重要的方法:
namespace App\\Providers;
use Illuminate\\Support\\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
# 注册服务.
public function register()
{
//
}
# 引导服务。
public function boot()
{
//
}
}
Laravel 在「引导」过程中干了两件重要的事:
1、通过 Service Provider 的 register() 方法注册「绑定」
2、所有 Servier Provider 的 register() 都执行完之后,再通过它们 boot() 方法,干一些别的事。
过程分析
这个「先后顺序」可以在 Laravel 的启动过程中找到:
1、首先,生成核心 Container : $app (实例化过程中还注册了一大堆基本的「绑定])
// public/index.php
$app = require_once __DIR__.'/../bootstrap/app.php';
// bootstrap/app.php
$app = new Illuminate\\Foundation\\Application(
realpath(__DIR__.'/../')
);
2、接下来注册 Http\\Kernel , Console\\Kernel , Debug\\ExecptionHandler
三个「单例」绑定:
// bootstrap/app.php
$app->singleton(
Illuminate\\Contracts\\Http\\Kernel::class,
App\\Http\\Kernel::class
);
$app->singleton(
Illuminate\\Contracts\\Console\\Kernel::class,
App\\Console\\Kernel::class
);
$app->singleton(
Illuminate\\Contracts\\Debug\\ExceptionHandler::class,
App\\Exceptions\\Handler::class
);
3、然后「启动」应用
// public/index.php
/*
|--------------------------------------------------------------------------
| Run The Application
|--------------------------------------------------------------------------
|
*/
$kernel = $app->make(Illuminate\\Contracts\\Http\\Kernel::class);
$response = $kernel->handle(
$request = Illuminate\\Http\\Request::capture()
);
4、由于以前的「绑定」,$kernel
获取的其实是 App\\Http\\Kernel
类的实例,App\\Http\\Kernel
类又继承了 Illuminate\\Foundation\\Http\\Kernel
类。 其 handle()
方法执行了 sendRequestThroughRouter()
方法:
// Illuminate\\Foundation\\Http
class Kernel implements KernelContract
{
public function handle($request)
try {
//...
$response = $this->sendRequestThroughRouter($request);
} catch (Exception $e) {
//...
}
}
}
5、这个 sendRequestThroughRouter()
方法执行了一系列 bootstrappers
(引导器)
// Illuminate\\Foundation\\Http
class Kernel implements KernelContract
{
protected function sendRequestThroughRouter($request)
{
//...
// 按顺序执行每个 bootstrapper
$this->bootstrap();
//...
}
}
6、bootstrap()
方法中又调用了 Illuminate\\Foundation\\Application
类的 bootstrapWith()
方法
// Illuminate\\Foundation\\Http
class Kernel implements KernelContract
{
public function bootstrap()
{
if (! $this->app->hasBeenBootstrapped()) {
$this->app->bootstrapWith($this->bootstrappers());
}
}
}
// Illuminate\\Foundation\\Http\\Kernel
class Kernel implements KernelContract
{
protected $bootstrappers = [
//...
\\Illuminate\\Foundation\\Bootstrap\\RegisterProviders::class, // 注册 Providers
\\Illuminate\\Foundation\\Bootstrap\\BootProviders::class, // 引导 Providers
];
protected function bootstrappers()
{
return $this->bootstrappers;
}
}
这里就能看出来 Service Provider 中 register 和 boot 的「先后顺序了」。
后续的执行过程暂时先不介绍了。
这就意味着,在 Service Provider boot 之前,已经把注册好了所有服务的「绑定」。因此, 在 boot() 方法中可以使用任何已注册的服务。 例如:
namespace App\\Providers;
use Illuminate\\Support\\ServiceProvider;
class ComposerServiceProvider extends ServiceProvider
{
public function boot()
{
// 这里使用 make() 方法,可以更直观
$this->app->make('view')->composer('view', function () {
//
});
// 或者使用 view() 辅助函数
view()->composer('view', function () {
//
});
}
}
如果了解 Container 「绑定」 和 make 的概念,应该很容易理解上面的过程。
剩下的无非就是:
创建 Service Provier
php artisan make:provider MyServiceProvider
注册绑定
namespace App\\Providers;
use Illuminate\\Support\\ServiceProvider;
class MyServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->bind(MyInterface::class, MyClass::class);
}
}
引导方法
namespace App\\Providers;
use Illuminate\\Support\\ServiceProvider;
use Illuminate\\Contracts\\Routing\\ResponseFactory;
class MyServiceProvider extends ServiceProvider
{
/**
* boot() 方法中可以使用依赖注入。
* 这是因为在 Illuminate\\Foundation\\Application 类中,
* 通过 bootProvider() 方法中的 $this->call([$provider, 'boot'])
* 来执行 Service Provider 的 boot() 方法
*/
public function boot(ResponseFactory $response)
{
$response->macro('caps', function ($value) {
//
});
}
}
在 config/app.php
中注册 Service Provider
'providers' => [
/*
* Laravel Framework Service Providers...
*/
/*
* Package Service Providers...
*/
/*
* Application Service Providers...
*/
App\\Providers\\MyServiceProvider::class,
],
注意:Laravel 5.5 之后有 package discovery 功能的 package 不需要在 config/app.php 中注册。
https://laravel.com/docs/5.5/packages#package-discovery
延时加载
按需加载,只有当 Container 「make」 ServiceProvider 类 providers() 方法中返回的值时,才会加载此 ServiceProvider。
例如:
namespace Illuminate\\Hashing;
use Illuminate\\Support\\ServiceProvider;
class HashServiceProvider extends ServiceProvider
{
# 如果延时加载,$defer 必须设置为 true 。
protected $defer = true;
# Register the service provider.
public function register()
{
$this->app->singleton('hash', function () {
return new BcryptHasher;
});
}
# Get the services provided by the provider.
public function provides()
{
return ['hash'];
}
}
当我们「make」时,才会注册 HashServiceProvider,即执行它的 register() 方法,进行 hash 的绑定:
class MyController extends Controller
{
public function test()
{
// 此时才会注册 `HashServiceProvider`
$hash = $this->app->make('hash');
$hash->make('teststring');
// 或
\\Hash::make('teststring');
}
}
以上是关于Laravel Service Provider 概念详解的主要内容,如果未能解决你的问题,请参考以下文章
Laravel Service Provider 开发时设置延迟加载时遇到的问题
Laravel 文档中的 Service Providers
[李景山php]每天laravel-20160831|EventServiceProvider