亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > PHP > 正文

Laravel服務提供器(ServiceProvider)的解讀

2020-03-22 19:51:28
字體:
來源:轉載
供稿:網友
這篇文章主要介紹了關于Laravel服務提供器(ServiceProvider)的解讀,有著一定的參考價值,現在分享給大家,有需要的朋友可以參考一下

服務提供器是所有 Laravel html' target='_blank'>應用程序引導中心。你的應用程序自定義的服務、第三方資源包提供的服務以及 Laravel 的所有核心服務都是通過服務提供器進行注冊(register)和引導(boot)的。

拿一個Laravel框架自帶的服務提供器來舉例子

class BroadcastServiceProvider extends ServiceProvider protected $defer = true; public function register() $this- app- singleton(BroadcastManager::class, function ($app) { return new BroadcastManager($app); $this- app- singleton(BroadcasterContract::class, function ($app) { return $app- make(BroadcastManager::class)- connection(); //將BroadcastingFactory::class設置為BroadcastManager::class的別名 $this- app- alias( BroadcastManager::class, BroadcastingFactory::class public function provides() return [ BroadcastManager::class, BroadcastingFactory::class, BroadcasterContract::class,}

在服務提供器BroadcastServiceProvider的register中, 為BroadcastingFactory的類名綁定了類實現BroadcastManager,這樣就能通過服務容器來make出通過BroadcastingFactory::class綁定的服務BroadcastManger對象供應用程序使用了。

本文主要時來梳理一下laravel是如何注冊、和初始化這些服務的,關于如何編寫自己的服務提供器,可以參考官方文檔

BootStrap

首先laravel注冊和引導應用需要的服務是發生在尋找路由處理客戶端請求之前的Bootstrap階段的,在框架的入口文件里我們可以看到,框架在實例化了Application對象后從服務容器中解析出了HTTP Kernel對象

$kernel = $app- make(Illuminate/Contracts/Http/Kernel::class);$response = $kernel- handle( $request = Illuminate/Http/Request::capture());

在Kernel處理請求時會先讓請求通過中間件然后在發送請求給路由對應的控制器方法, 在這之前有一個BootStrap階段來引導啟動Laravel應用程序,如下面代碼所示。

public function handle($request) ...... $response = $this- sendRequestThroughRouter($request); ...... return $response;}
protected function sendRequestThroughRouter($request) $this- app- instance( request , $request); Facade::clearResolvedInstance( request  $this- bootstrap(); return (new Pipeline($this- app)) - send($request) - through($this- app- shouldSkipMiddleware() ? [] : $this- middleware) - then($this- dispatchToRouter());//引導啟動Laravel應用程序public function bootstrap() if (! $this- app- hasBeenBootstrapped()) { /**依次執行$bootstrappers中每一個bootstrapper的bootstrap()函數 $bootstrappers = [ Illuminate/Foundation/Bootstrap/DetectEnvironment , Illuminate/Foundation/Bootstrap/LoadConfiguration , Illuminate/Foundation/Bootstrap/ConfigureLogging , Illuminate/Foundation/Bootstrap/HandleExceptions , Illuminate/Foundation/Bootstrap/RegisterFacades , Illuminate/Foundation/Bootstrap/RegisterProviders , Illuminate/Foundation/Bootstrap/BootProviders , ];*/ $this- app- bootstrapWith($this- bootstrappers()); }

上面bootstrap中會分別執行每一個bootstrapper的bootstrap方法來引導啟動應用程序的各個部分

 1. DetectEnvironment 檢查環境 2. LoadConfiguration 加載應用配置 3. ConfigureLogging 配置日至 4. HandleException 注冊異常處理的Handler 5. RegisterFacades 注冊Facades  6. RegisterProviders 注冊Providers  7. BootProviders 啟動Providers

啟動應用程序的最后兩部就是注冊服務提供這和啟動提供者,如果對前面幾個階段具體時怎么實現的可以參考這篇文章。在這里我們主要關注服務提供器的注冊和啟動。

先來看注冊服務提供器,服務提供器的注冊由類 /Illuminate/Foundation/Bootstrap/RegisterProviders::class 負責,該類用于加載所有服務提供器的 register 函數,并保存延遲加載的服務的信息,以便實現延遲加載。

class RegisterProviders public function bootstrap(Application $app) //調用了Application的registerConfiguredProviders() $app- registerConfiguredProviders();class Application extends Container implements ApplicationContract, HttpKernelInterface public function registerConfiguredProviders() (new ProviderRepository($this, new Filesystem, $this- getCachedServicesPath())) - load($this- config[ app.providers  public function getCachedServicesPath() return $this- bootstrapPath(). /cache/services.php }

可以看出,所有服務提供器都在配置文件 app.php 文件的 providers 數組中。類 ProviderRepository 負責所有的服務加載功能:

class ProviderRepository public function load(array $providers) $manifest = $this- loadManifest(); if ($this- shouldRecompile($manifest, $providers)) { $manifest = $this- compileManifest($providers); foreach ($manifest[ when ] as $provider = $events) { $this- registerLoadEvents($provider, $events); foreach ($manifest[ eager ] as $provider) { $this- app- register($provider); $this- app- addDeferredServices($manifest[ deferred }

loadManifest()會加載服務提供器緩存文件services.php,如果框架是第一次啟動時沒有這個文件的,或者是緩存文件中的providers數組項與config/app.php里的providers數組項不一致都會編譯生成services.php。

//判斷是否需要編譯生成services文件public function shouldRecompile($manifest, $providers) return is_null($manifest) || $manifest[ providers ] != $providers;//編譯生成文件的具體過程protected function compileManifest($providers) $manifest = $this- freshManifest($providers); foreach ($providers as $provider) { $instance = $this- createProvider($provider); if ($instance- isDeferred()) { foreach ($instance- provides() as $service) { $manifest[ deferred ][$service] = $provider; $manifest[ when ][$provider] = $instance- when(); else { $manifest[ eager ][] = $provider; return $this- writeManifest($manifest);
return [ providers = $providers, eager = [], deferred = []];}

緩存文件中 providers 放入了所有自定義和框架核心的服務。

如果服務提供器是需要立即注冊的,那么將會放入緩存文件中 eager 數組中。

如果服務提供器是延遲加載的,那么其函數 provides() 通常會提供服務別名,這個服務別名通常是向服務容器中注冊的別名,別名將會放入緩存文件的 deferred 數組中,與真正要注冊的服務提供器組成一個鍵值對。

延遲加載若由 event 事件激活,那么可以在 when 函數中寫入事件類,并寫入緩存文件的 when 數組中。

生成的緩存文件內容如下:

array ( providers =  array ( 0 = Illuminate//Auth//AuthServiceProvider , 1 = Illuminate//Broadcasting//BroadcastServiceProvider , eager =  array ( 0 = Illuminate//Auth//AuthServiceProvider , 1 = Illuminate//Cookie//CookieServiceProvider , deferred =  array ( Illuminate//Broadcasting//BroadcastManager = Illuminate//Broadcasting//BroadcastServiceProvider , Illuminate//Contracts//Broadcasting//Factory = Illuminate//Broadcasting//BroadcastServiceProvider , when =  array ( Illuminate//Broadcasting//BroadcastServiceProvider =  array ()
事件觸發時注冊延遲服務提供器

延遲服務提供器除了利用 IOC 容器解析服務方式激活,還可以利用 Event 事件來激活:

protected function registerLoadEvents($provider, array $events) if (count($events) 1) { return; $this- app- make( events )- listen($events, function () use ($provider) { $this- app- register($provider);}
即時注冊服務提供器

需要即時注冊的服務提供器的register方法由Application的register方法里來調用:

class Application extends Container implements ApplicationContract, HttpKernelInterface public function register($provider, $options = [], $force = false) if (($registered = $this- getProvider($provider)) ! $force) { return $registered; if (is_string($provider)) { $provider = $this- resolveProvider($provider); if (method_exists($provider, register )) { $provider- register(); $this- markAsRegistered($provider); if ($this- booted) { $this- bootProvider($provider); return $provider; public function getProvider($provider) $name = is_string($provider) ? $provider : get_class($provider); return Arr::first($this- serviceProviders, function ($value) use ($name) { return $value instanceof $name; public function resolveProvider($provider) return new $provider($this); protected function markAsRegistered($provider) //這個屬性在稍后booting服務時會用到 $this- serviceProviders[] = $provider; $this- loadedProviders[get_class($provider)] = true; protected function bootProvider(ServiceProvider $provider) if (method_exists($provider, boot )) { return $this- call([$provider, boot }

可以看出,服務提供器的注冊過程:

判斷當前服務提供器是否被注冊過,如注冊過直接返回對象

解析服務提供器

調用服務提供器的 register 函數

標記當前服務提供器已經注冊完畢

若框架已經加載注冊完畢所有的服務容器,那么就啟動服務提供器的 boot 函數,該函數由于是 call 調用,所以支持依賴注入。

服務解析時注冊延遲服務提供器

延遲服務提供器首先需要添加到 Application 中

public function addDeferredServices(array $services) $this- deferredServices = array_merge($this- deferredServices, $services);}

我們之前說過,延遲服務提供器的激活注冊有兩種方法:事件與服務解析。

當特定的事件被激發后,就會調用 Application 的 register 函數,進而調用服務提供器的 register 函數,實現服務的注冊。

當利用 Ioc 容器解析服務名時,例如解析服務名 BroadcastingFactory:

class BroadcastServiceProvider extends ServiceProvider protected $defer = true; public function provides() return [ BroadcastManager::class, BroadcastingFactory::class, BroadcasterContract::class,}

在Application的make方法里會通過別名BroadcastingFactory查找是否有對應的延遲注冊的服務提供器,如果有的話那么
就先通過registerDeferredProvider方法注冊服務提供器。

class Application extends Container implements ApplicationContract, HttpKernelInterface public function make($abstract) $abstract = $this- getAlias($abstract); if (isset($this- deferredServices[$abstract])) { $this- loadDeferredProvider($abstract); return parent::make($abstract); public function loadDeferredProvider($service) if (! isset($this- deferredServices[$service])) { return; $provider = $this- deferredServices[$service]; if (! isset($this- loadedProviders[$provider])) { $this- registerDeferredProvider($provider, $service);}

由 deferredServices 數組可以得知,BroadcastingFactory 為延遲服務,接著程序會利用函數 loadDeferredProvider 來加載延遲服務提供器,調用服務提供器的 register 函數,若當前的框架還未注冊完全部服務。那么將會放入服務啟動的回調函數中,以待服務啟動時調用:

public function registerDeferredProvider($provider, $service = null) if ($service) { unset($this- deferredServices[$service]); $this- register($instance = new $provider($this)); if (! $this- booted) { $this- booting(function () use ($instance) { $this- bootProvider($instance);}

還是拿服務提供器BroadcastServiceProvider來舉例:

class BroadcastServiceProvider extends ServiceProvider protected $defer = true; public function register() $this- app- singleton(BroadcastManager::class, function ($app) { return new BroadcastManager($app); $this- app- singleton(BroadcasterContract::class, function ($app) { return $app- make(BroadcastManager::class)- connection(); //將BroadcastingFactory::class設置為BroadcastManager::class的別名 $this- app- alias( BroadcastManager::class, BroadcastingFactory::class public function provides() return [ BroadcastManager::class, BroadcastingFactory::class, BroadcasterContract::class,}

函數 register 為類 BroadcastingFactory 向 服務容器綁定了特定的實現類 BroadcastManager,Application中的 make 函數里執行parent::make($abstract) 通過服務容器的make就會正確的解析出服務 BroadcastingFactory。

因此函數 provides() 返回的元素一定都是 register() 向 服務容器中綁定的類名或者別名。這樣當我們利用App::make() 解析這些類名的時候,服務容器才會根據服務提供器的 register() 函數中綁定的實現類,正確解析出服務功能。

啟動Application

Application的啟動由類 /Illuminate/Foundation/Bootstrap/BootProviders 負責:

class BootProviders public function bootstrap(Application $app) $app- boot();class Application extends Container implements ApplicationContract, HttpKernelInterface public function boot() if ($this- booted) { return; $this- fireAppCallbacks($this- bootingCallbacks); array_walk($this- serviceProviders, function ($p) { $this- bootProvider($p); $this- booted = true; $this- fireAppCallbacks($this- bootedCallbacks); protected function bootProvider(ServiceProvider $provider) if (method_exists($provider, boot )) { return $this- call([$provider, boot }

引導應用Application的serviceProviders屬性中記錄的所有服務提供器,就是依次調用這些服務提供器的boot方法,引導完成后$this- booted = true 就代表應用Application正式啟動了,可以開始處理請求了。這里額外說一句,之所以等到所有服務提供器都注冊完后再來進行引導是因為有可能在一個服務提供器的boot方法里調用了其他服務提供器注冊的服務,所以需要等到所有即時注冊的服務提供器都register完成后再來boot。

以上就是本文的全部內容,希望對大家的學習有所幫助,更多相關內容請關注PHP !

相關推薦:

Laravel控制器的解讀

Laravel核心解讀Response

以上就是Laravel服務提供器(ServiceProvider)的解讀的詳細內容,PHP教程

鄭重聲明:本文版權歸原作者所有,轉載文章僅為傳播更多信息之目的,如作者信息標記有誤,請第一時間聯系我們修改或刪除,多謝。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
国产91在线播放九色快色| 国产美女久久精品香蕉69| 欧美精品免费看| 欧美黑人视频一区| 亚洲区一区二区| 久久久视频精品| 国产精品日日做人人爱| 国产精品视频自在线| 国产精品男女猛烈高潮激情| 久久夜精品va视频免费观看| 国产精品人人做人人爽| 国产狼人综合免费视频| 久久精品国亚洲| 三级精品视频久久久久| 黑人巨大精品欧美一区二区免费| 欧美日韩激情视频8区| 日韩电影中文 亚洲精品乱码| 尤物yw午夜国产精品视频| 国产偷亚洲偷欧美偷精品| 欧美插天视频在线播放| 亚洲男人天堂2023| 久久久久国产一区二区三区| 日韩欧美在线网址| 欧美成人精品一区| 久久91精品国产91久久久| 国产精品免费小视频| 亚洲一区二区久久久久久| 在线激情影院一区| 国产日韩欧美视频在线| 日本道色综合久久影院| 国产福利精品av综合导导航| 欧美国产中文字幕| 91久久夜色精品国产网站| 69久久夜色精品国产69乱青草| 国产91在线播放九色快色| 奇米4444一区二区三区| 国产精品美女www| 精品无码久久久久久国产| 欧美色视频日本高清在线观看| 中文字幕亚洲综合久久| www.亚洲男人天堂| 日韩在线观看网址| 国产精品久久久久久久久久尿| 日韩电影中文字幕一区| 精品福利视频导航| 在线看日韩欧美| 国产精品三级久久久久久电影| 亚洲在线www| 欧美插天视频在线播放| 日韩欧美成人免费视频| 亚洲丁香婷深爱综合| 亚洲国产精久久久久久久| 国产精品羞羞答答| 欧美另类交人妖| 欧美性感美女h网站在线观看免费| 久久中文字幕一区| 日韩av片电影专区| 91日本在线视频| 欧美一区二粉嫩精品国产一线天| 亚洲欧美日韩精品久久亚洲区| 亚洲人成自拍网站| 精品国内自产拍在线观看| 亚洲乱码一区二区| 欧美激情精品久久久久久蜜臀| 91亚洲精品久久久| 国产精品69精品一区二区三区| 亚洲第一精品福利| 欧美视频精品一区| 欧美精品videos性欧美| 亚洲xxxx在线| 人体精品一二三区| 96sao精品视频在线观看| 亚洲视频在线免费看| 日韩美女在线看| 国产成人精品在线视频| 亚洲欧洲xxxx| 亚洲欧洲偷拍精品| 久久精品在线播放| 亚洲天堂av在线免费| 在线播放国产一区中文字幕剧情欧美| 亚洲最大的成人网| 国产精品久久久久一区二区| 国产精品久久久久久av福利软件| 欧美日韩免费在线观看| 久久琪琪电影院| 亚洲人成网站777色婷婷| 久久精品在线播放| 欧美日韩国产成人在线| 在线观看日韩专区| 伊人伊人伊人久久| 中文字幕日韩av电影| 国a精品视频大全| 琪琪第一精品导航| 欧美成人自拍视频| 日韩亚洲第一页| 久久久在线免费观看| 精品美女永久免费视频| 国产脚交av在线一区二区| 黑人精品xxx一区| 精品久久香蕉国产线看观看gif| 久久在线观看视频| 色诱女教师一区二区三区| 日韩精品欧美国产精品忘忧草| 欧美高清第一页| 国产精品久久久久免费a∨| 欧美激情第6页| 热99精品只有里视频精品| 911国产网站尤物在线观看| 欧美日韩在线视频一区二区| 日韩久久精品电影| 精品自拍视频在线观看| 久久6精品影院| 亚洲第一精品久久忘忧草社区| 97国产成人精品视频| 久久久亚洲天堂| 在线观看日韩欧美| 欧美老妇交乱视频| 91网在线免费观看| 色樱桃影院亚洲精品影院| 日韩美女视频免费在线观看| 日韩av综合中文字幕| 欧美激情小视频| 国产成人精品久久二区二区91| 欧美高跟鞋交xxxxxhd| 日韩视频免费在线| 九九精品视频在线| 国产精品一区二区三| 国产亚洲精品久久久久久777| 情事1991在线| 97视频免费在线看| 久久久久久久久国产精品| 久久人人爽人人爽人人片av高请| 国产网站欧美日韩免费精品在线观看| 亚洲第一网站免费视频| 国产精品av在线播放| 亚洲a区在线视频| 成人网在线观看| 91久久国产精品91久久性色| 欧美日韩国产一区在线| 北条麻妃一区二区在线观看| 欧美一级片免费在线| 欧美日韩精品在线播放| 国产精品久久久一区| 成人网在线观看| 美女视频久久黄| 欧美精品免费在线| 亚洲的天堂在线中文字幕| 热门国产精品亚洲第一区在线| 亚洲美腿欧美激情另类| 亚洲精品720p| 91精品国产91久久久久久| 欧美性猛交xxxx乱大交3| 亚洲欧美激情一区| 成人深夜直播免费观看| 成人午夜在线观看| 狠狠色狠狠色综合日日小说| 国产亚洲一区二区在线| 国产成人极品视频| 欧美性精品220| 人人澡人人澡人人看欧美| 欧美视频裸体精品| 91在线观看免费网站| 欧美性猛交xxxx富婆| 上原亚衣av一区二区三区|