laravel的模塊化是如何實現的


laravel的模塊化是如何實現的

在laravel提供的官方文檔上,有一個這樣的名詞 服務提供者,文檔中介紹了它在laravel框架中的角色,以及如何使用它,但卻沒有講明服務提供者的本質--它是為了解決什么問題而存在的? 不解決這一點,對於它的理解,則只會停留在表面.服務提供者是laravel實現模塊化設計的手法.

為什么要進行模塊化設計這里就不說的,可以參考下這些:模塊化設計 , 模塊化的意義何在?

為了實現模塊化,必然要將一段程序組合起來,完成特定的事,從而形成模塊.在laravel中, 一個模塊都表現為一個Service.應用程序主體與組件(模塊)之間必然要通過某種方式連接起來,才能使組件被主體所調用.在laravel中一個Service會被它的 Service Prorider 注入到ioc中,這樣組件就與主體聯系了起來, 具體的表現形式則是組件被主體所用,主體使用組件完成組件所擅長的事. 源代碼是最好的文檔,接下來,我們就看看"文檔"是怎么說的.

laravel的啟動過程

我們從啟動開始,詳細地分析在整個應用程序的生命周期中,Service Provider到底是什么?通過閱讀源碼方式來了解Serivce Provider在laravel中到底做了什么.

laravle的啟動過程做了很多事,這里就不一一敘述了,主要說明有關Sevice Provider的部分.laravel有兩個入口分別處理不同的請求1:public/index.php(http) 2.php arisan(cli).雖然入口有兩種但它們的啟動過程卻相差無幾(具體可以再詳細了解這兩種方式).

基礎啟動

bootstrap/app.php則是它的主要啟動文件, 在\Illuminate\Foundation\Application::__construct中就可以看到應用主體的啟動做了什么:

  • 綁定Appliation和Container
  • 注冊最基礎的Service Provider
  • 注冊別名
  • 注冊該應用程序的路徑

上面啟動過程的代碼較簡單,代碼不分析了.就說一說為什么要做這幾步,以及這幾步對lavarel有什么作用.

laravel中以ioc為基礎來構建應用程序的,所以,把這個最基礎的Applicatoin放入容器中,供需要時可以隨時從容器中提取使用(container 與 Application的關系看看代碼就清晰了).

一個應用的合理運行必然離不開一些最基本的功能點,就像人類一樣,雖然最重要的是大腦,但同樣也不能沒有血管,心臟.所以在laravel中也同樣存在一些不可或缺的service provider, 比如事件和路由器.\Illuminate\Events\EventServiceProvider則把構建觀察者的類注入到了ioc中,同時,在laravel源代碼中大量使用了觀察者模式來處理問題,\Illuminate\Routing\RoutingServiceProvider則把路由相關的服務注入到了主體中,因為一個http請求最不可或缺的當然是路由;

注冊別名,則是為了調用ioc中的類時更方便,還有一點要注意是的,可以為一個類注冊多個別名,為什么呢,其實這多個別名是存在關系的,它們大多是父類與子類的關系,就像Appliation和Container;

注冊應用的路徑則把一樣常用的,跟應用有關的路徑放到ioc中方便取用.啟動的第一步到這就結束了.

http應用請求的啟動

緊接着,又注冊了三個類到ioc中,分別是http處理核心類,cli處理核心類,和異常處理.在這里注冊了兩種不同請親的處理類,所以兩個請求入口所做的事情都差不多了.接下來以http請求為例來,繼續看下去.public/index.php:50則初始化了\App\Http\Kernel::__construct,也就初始化了中間件.接着public/index.php:52則調用了\Illuminate\Foundation\Http\Kernel::handle來處理請求,進一步看下去,也就是\Illuminate\Foundation\Http\Kernel::bootstrap中通過Application::bootstrapWith完成http請求環境的初始化,具體則是:

  • 標記Application為已經引導啟動狀態
  • 依次啟動\Illuminate\Foundation\Http\Kernel::$bootstrappers中的項目
    1.Illuminate\Foundation\Bootstrap\DetectEnvironment:設置應用程序的環境
    2.Illuminate\Foundation\Bootstrap\LoadConfiguration:載入應用程序的配置文件
    3.Illuminate\Foundation\Bootstrap\ConfigureLogging:綁定日志處理類
    4.Illuminate\Foundation\Bootstrap\HandleExceptions:異常處理
    5.Illuminate\Foundation\Bootstrap\RegisterFacades:Facade模式的應用
    6.Illuminate\Foundation\Bootstrap\RegisterProviders:注冊Service Provider
    7.Illuminate\Foundation\Bootstrap\BootProviders:標記啟動完成 , 執行Srvice Providerregister方法,完成注入

然后,在vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php:129就進入到了路由器,進而進入對應Controller進行處理,最后完成處理,請求結束.這一部分就不說了.

cli請求的啟動

這一部分略,步驟與http類似

從它的請求生命周期可以看出以下幾點
1:Service Provider在啟動階段就已經與注入了IOC
2:分為了兩種,一種是由系統控制,而另一種則是可由用戶控制.第一種是構成應用程序的基礎,不能缺少;第二種則將控制權交給用戶,由用戶掌控應用的運行,比如加載第三方composer包,或自定義的Service等等.

此時,模塊化已經初現雛形.在Controller中,可以調用或組合不同的Service, 來完成特定的邏輯,因為它已經在IOC中了;我們可以控制不同的Service或增或減,自定義這個應用程序的功能,成為新的系統.接下來,再看看Service Provider做了什么,使模塊化在laravel中更完善.

注冊Service Provider

在注冊基礎的Service Provider中,不難發現,完成注冊過程的是\Illuminate\Foundation\Application::register,這個方法比較簡單,一是執行了ServierProceder::register方法,通過這個接口將Service注冊動IOC中;二是在系統已經啟動的情況下,執行ServierProceder::boot方法,作用在這里講的很清楚.

在注冊用戶自定義(config/app.php:124)時,\Illuminate\Foundation\Application::registerConfiguredProviders則完成了注冊過程,其處理核心\Illuminate\Foundation\ProviderRepository::load主要做了以下幾步
1:解析所有的Service Provider, 通過它的defer屬性來決定是否延遲加載
2:將解析的結果,也就是一個Service Provider的數組,緩存為文件,下次直接載入解析后的緩存文件
3:只加載defer屬性不為ture的Service Provider, 並注冊
4:將延遲加載的放支容器中(APP::$deferredServices),在需要的時候再加載

從注冊過程可以看出,我們可以定義Service Provider加載的時間,並不僅僅在啟動這過程中加載,而是在需要的時候再加載.一種是通過\Illuminate\Foundation\Application::make;還有一種方式延遲加載則是在when方法中通過事件注冊到某項事件上去,這一點則要好好看看\Illuminate\Foundation\ProviderRepository類了.

理清它的注冊過程后,我們再仔細看看Service Provider的抽象類,它作為基類,提供了Servicer Provider能做的所有事情.了解它能更好的理解Service Provider.這個類並不復雜,唯一一個不是很清晰的只有commands方法:它將命令注冊到了\Illuminate\Console\Events\ArtisanStarting事件中,為什么這樣做? 在cli時,啟動時,會有該事件的執行,從而通過Service Provider把命令注入到了IOC中,這樣執行命令就行雲流水了.

到這里,用Service Provider來實現模塊化的功能得到了強化,既可以延遲加載,還可以注冊命令.接下來,通過一些例子,看看它具體做了什么.

Service Provider的使用

Service Provider有很多,我們隨便挑兩個來看看

QueueServiceProvider

\Illuminate\Queue\QueueServiceProvider並非系統控制級別,看源代碼,可以發現,里面有很多注冊方法,注冊了很多有關隊列的類到IOC中,同時也注冊了很多命令.在provides方法中,它返回的就是一個所有在這個Service Provider出現的的各個類,它是做什么的?其實我們可以發現,這個Service Provider是延遲加載的,所以這個Service所提供的各種服務並不會出現在服務中,上面我們說過,在需要的時候再加載.這一功能就是由provides中的返回值來決定的,當調用IOC中,那些延遲加載服務中出現的那些類時,再加載這些延遲的服務,從而可以獲得延遲服務所提供的服務.

EventServiceProvider

\Illuminate\Events\EventServiceProvider是應用程序的核心,它又做了什么呢?
它也是向IOC中注冊了事件處理的類,同時為這個類設置了隊列解析的類.

HashServiceProvider

\Illuminate\Hashing\HashServiceProvider也向IOC注冊一hash處理的類,並且是延遲加載的.

小結

查看Service Provicer的使用后,我們可以發現,它們都做了同們的事,就是把相應的服務注入到ICO中,以供使用,從而構成完成的系統.所以,現在我們就可以明白Service Provider是lararel完成模塊化設計的方法,只不過融入了一些laravel自己的特點.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM