【Laravel-海贼王系列】第四章,Kernel 类解析

790 阅读2分钟

我们将进入 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);
    }
}

构造完成之后将获得一个包含路由和中间件的内核对象, 接着我们解析内核的重要方法。

主要方法解析

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());
                

}

终止应用

public function terminate($request, $response)
{
    // "开始遍历所有中间件中的终止方法,如果有则立即调用。"
    $this->terminateMiddleware($request, $response);

    // "调用app对象$terminatingCallbacks中的所有回调"
    $this->app->terminate();
}

总结

内核主要是处理请求,终止请求的功能。

其中还包括了加载app的一些必要的服务,比如配置,异常等类都是

在内核的handler过程中加载的。

还包含了路由对请求的转发,以及通过管道来发送请求是通过中间件等等。