【Laravel-海賊王系列】第四章,Kernel 類解析

咱們將進入 Kernel 的世界看看laravel是怎麼啓動的。

頭部申明

namespace App\Http;

use Illuminate\Foundation\Http\Kernel as HttpKernel;

class Kernel extends HttpKernel // "繼承於Http內核"
複製代碼

成員變量

// "自身成員應用全局中間件,運行於每個請求"
protected $middleware = [
    \App\Http\Middleware\CheckForMaintenanceMode::class,
    \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
    \App\Http\Middleware\TrimStrings::class,
    \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
    \App\Http\Middleware\TrustProxies::class,
];

// "應用路由中間件組"
protected $middlewareGroups = [
    'web' => [
        \App\Http\Middleware\EncryptCookies::class,
        \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
        \Illuminate\Session\Middleware\StartSession::class,
        // \Illuminate\Session\Middleware\AuthenticateSession::class,
        \Illuminate\View\Middleware\ShareErrorsFromSession::class,
        \App\Http\Middleware\VerifyCsrfToken::class,
        \Illuminate\Routing\Middleware\SubstituteBindings::class,
    ],

    'api' => [
        'throttle:60,1',
        'bindings',
    ],
];

// "應用路由中間件,能夠分配給組也能夠單獨"
protected $routeMiddleware = [
    'auth' => \App\Http\Middleware\Authenticate::class,
    'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
    'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
    'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
    'can' => \Illuminate\Auth\Middleware\Authorize::class,
    'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
    'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
    'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
    'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
];

// "強制非全局中間件始終按給定順序。"
protected $middlewarePriority = [
    \Illuminate\Session\Middleware\StartSession::class,
    \Illuminate\View\Middleware\ShareErrorsFromSession::class,
    \App\Http\Middleware\Authenticate::class,
    \Illuminate\Session\Middleware\AuthenticateSession::class,
    \Illuminate\Routing\Middleware\SubstituteBindings::class,
    \Illuminate\Auth\Middleware\Authorize::class,
];  

// "繼承Http Kernel成員"

// "Application實例"
protected $app; 

// "\Illuminate\Routing\Router 路由實例"
protected $router;

// "應用須要引導的類"
protected $bootstrappers = [
    \Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables::class,
    \Illuminate\Foundation\Bootstrap\LoadConfiguration::class,
    \Illuminate\Foundation\Bootstrap\HandleExceptions::class,
    \Illuminate\Foundation\Bootstrap\RegisterFacades::class,
    \Illuminate\Foundation\Bootstrap\RegisterProviders::class,
    \Illuminate\Foundation\Bootstrap\BootProviders::class,
]; 

// "應用中間件堆棧"
protected $middleware = [];

// "應用中間件組"
protected $middlewareGroups = [];

// "路由中間件"
protected $routeMiddleware = [];

// "強制非全局中間件始終按給定順序。"
protected $middlewarePriority = [
    \Illuminate\Session\Middleware\StartSession::class,
    \Illuminate\View\Middleware\ShareErrorsFromSession::class,
    \Illuminate\Auth\Middleware\Authenticate::class,
    \Illuminate\Session\Middleware\AuthenticateSession::class,
    \Illuminate\Routing\Middleware\SubstituteBindings::class,
    \Illuminate\Auth\Middleware\Authorize::class,
]; 
    
複製代碼

構造函數(繼承自http kernel)

public function __construct(Application $app, Router $router) 

// "經過容器的build方法自動找出全部的依賴進行實例化傳入。"
// "調用鏈是 $app->make() 到 $container->make(),$container->resolve(),$container->build()。"
{
    $this->app = $app;
    
     // "將實例化的路由對象賦值給成員"
    $this->router = $router;

    // "將中間件強制順序組傳給路由"
    $router->middlewarePriority = $this->middlewarePriority;

    // "遍歷全部中間件組傳給路由的組對應"
    foreach ($this->middlewareGroups as $key => $middleware) {
        $router->middlewareGroup($key, $middleware);
    }

    // "遍歷成員,將值賦值給路由別名"
    foreach ($this->routeMiddleware as $key => $middleware) {
        $router->aliasMiddleware($key, $middleware);
    }
}
複製代碼

構造完成以後將得到一個包含路由和中間件的內核對象, 接着咱們解析內核的重要方法。php

主要方法解析

public function handle($request) // 接收一個 Illuminate\Http\Request 請求對象
{
    try {
        // "啓用http方法參數覆蓋,可能致使CSRF攻擊。"
        $request->enableHttpMethodParameterOverride(); 
        
        // "下面解析這個方法"
        $response = $this->sendRequestThroughRouter($request); 
    } catch (Exception $e) {
        $this->reportException($e);

        $response = $this->renderException($request, $e);
    } catch (Throwable $e) {
        // "異常處理相關"
        $this->reportException($e = new FatalThrowableError($e));

        $response = $this->renderException($request, $e);
    } 

    // "因爲容器繼承了ArrayAccess此處的$this->app['events']會轉到容器的__get()方法, __get()會調用容器的offsetGet('events')方法中解析出events實例。這涉及ArrayAccess類的特性。 這裏實現了觸發一個RequestHandled的事件"

    $this->app['events']->dispatch(
        new Events\RequestHandled($request, $response)
    ); 
   
    return $response;
}
複製代碼
protected function sendRequestThroughRouter($request)
{
    // "將request實例放入app的$instances成員"
    $this->app->instance('request', $request); 

    // "清理已經解析成員中對應的request的值。"
    Facade::clearResolvedInstance('request');

    $this->bootstrap(); 
    
    // "開始啓動引導,傳入$bootstrappers成員給app對象的bootstrapWith(array $bootstrappers)方法, 這裏主要作了幾件事 1.觸發應用啓動前listen的同名事件 2.從容器中make出實例而且調用自己的bootstrap()方法來啓動。"
    
    // "載入環境變量env"
    \Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables::class,

    // "載入config文件夾下的配置文件"
    \Illuminate\Foundation\Bootstrap\LoadConfiguration::class,

    // "make php異常處理和相關報告"
    \Illuminate\Foundation\Bootstrap\HandleExceptions::class,

    // "make 全部的門面app.aliases和PackageManifest::class)->aliases()中的類"
    \Illuminate\Foundation\Bootstrap\RegisterFacades::class,

    // "make config下app.providers中的類"
    \Illuminate\Foundation\Bootstrap\RegisterProviders::class,

    // "調用app自身的boot(),觸發全部的 $bootingCallbacks 回調,調用 $serviceProviders 全部的類的 boot 方法,觸發全部的bootedCallbacks回調。"
    \Illuminate\Foundation\Bootstrap\BootProviders::class,
    
    // "3.觸發應用啓動後listen的同名事件 這裏將經過app和容器來加載env,config目錄下的文件,設置php異常配置,加載config/app.php配置的門面類,加載config/app.php服務提供者類,最後啓動app對象自身boot();"
    

    // "經過管道來處理中間件,而後將處理後的請求又路由轉發,最後獲得response對象。"
    return (new Pipeline($this->app))
                ->send($request)
                ->through($this->app->shouldSkipMiddleware() ? [] : $this->middleware)
                ->then($this->dispatchToRouter());
                

}
複製代碼

終止應用laravel

public function terminate($request, $response)
{
    // "開始遍歷全部中間件中的終止方法,若是有則當即調用。"
    $this->terminateMiddleware($request, $response);

    // "調用app對象$terminatingCallbacks中的全部回調"
    $this->app->terminate();
}
複製代碼

總結

內核主要是處理請求,終止請求的功能。web

其中還包括了加載app的一些必要的服務,好比配置,異常等類都是bootstrap

在內核的handler過程當中加載的。api

還包含了路由對請求的轉發,以及經過管道來發送請求是經過中間件等等。bash

相關文章
相關標籤/搜索