laravel请求处理流程源码分析
7人赞赏了该文章
372次浏览
编辑于2018年07月08日 20:22:34
请求处理的入口文件是index.php,其主要作用是提供请求处理的统一入口,生成并初始化一个应用实例(这里实质上是一个服务容器)app,获取一个http请求处理实例kernel,获取并初始化一个请求实例request,通过kernel处理request,得到相应response index.php的主要内容如下
<?php/* 引入composer的自动加载文件,引入后就可以直接使用vender目录下的第三方扩展库了 */require __DIR__.'/../bootstrap/autoload.php';/* 获取全局应用实例app,该实例app是一个服务容器,在整个请求的生命周期中用到的服务都是在该容器中注册和获取的 */$app = require_once __DIR__.'/../bootstrap/app.php';/* 从服务容器中获取kernel服务,该服务包括处理整个http请求的功能 */$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);/* 处理本次请求,并获取返回的结果 处理过程包括在服务容器中进程相关的服务注册、应用中间件、路由分配等 */$response = $kernel->handle( /* 获取当前请求的实例,该实例中包含了该次请求所包含的信息,包括请求方法、url、请求参数等 */ $request = Illuminate\Http\Request::capture() );$response->send();$kernel->terminate($request, $response);
bootstrap/autoload.php的内容如下
<?phpdefine('LARAVEL_START', microtime(true));/* 引入composer的自动加载文件,该文件执行了项目根目录下的composer.json和vender目录下的各第三方扩展库的composer.json中定义的自动加载规则,得到结果如下: 1.对于本项目的composer.json文件中autoload下的files,直接require其定义的文件 2.对于本项目的composer.json文件中autoload下的psr-4,在需要时会自动加载以其定义的命名空间前缀开头的文件 3.对于本项目的composer.json文件中autoload下classmap,在需要时会扫描其定义的目录或文件 4.执行vender目录下的各第三方扩展库的composer.json中定义的自动加载规则,将第三方扩展库的类加入自动加载,需要时可直接使用 */require __DIR__.'/../vendor/autoload.php';$compiledPath = __DIR__.'/cache/compiled.php';if (file_exists($compiledPath)) { require $compiledPath; }
bootstrap/app.php的内容如下
<?php/* 得到一个全局的应用实例$app,该实例实际上是一个服务容器,可以在其中注册和获取服务 */$app = new Illuminate\Foundation\Application( realpath(__DIR__.'/../') );/* 在$app中注册一个Http\Kernel的服务,该服务用于处理http的请求 */$app->singleton( Illuminate\Contracts\Http\Kernel::class, App\Http\Kernel::class );/* 在$app中注册一个Console\Kernel的服务,该服务用于处理命令行的请求 */$app->singleton( Illuminate\Contracts\Console\Kernel::class, App\Console\Kernel::class );$app->singleton( Illuminate\Contracts\Debug\ExceptionHandler::class, App\Exceptions\Handler::class );return $app;
bootstrap/app.php中在得到$app时进行了一些初始化的动作,初始化的内容如下
public function __construct($basePath = null){ /* 将应用实例$app注册到服务容器中,提供全局获取应用实例的方式 */ $this->registerBaseBindings(); /* 在容器中注册事件服务和路由服务 */ $this->registerBaseServiceProviders(); /* 将一些核心服务的别名设置到服务容器的别名数组中 */ $this->registerCoreContainerAliases(); if ($basePath) { /* 将项目核心目录的路径注册到容器中 */ $this->setBasePath($basePath); } }
index.php中处理请求的逻辑如下
$response = $kernel->handle( $request = Illuminate\Http\Request::capture() );
请求的处理都在handle中完成,handle的逻辑如下
public function handle($request){ try { $request->enableHttpMethodParameterOverride(); /* 请求处理的核心逻辑 */ $response = $this->sendRequestThroughRouter($request); } catch (Exception $e) { $this->reportException($e); $response = $this->renderException($request, $e); } catch (Throwable $e) { $e = new FatalThrowableError($e); $this->reportException($e); $response = $this->renderException($request, $e); } $this->app['events']->fire('kernel.handled', [$request, $response]); return $response; }
其中处理请求的核心逻辑是在sendRequestThroughRouter中完成的,该方法的内容如下
protected function sendRequestThroughRouter($request){ $this->app->instance('request', $request); Facade::clearResolvedInstance('request'); /* 在这里会启动一些核心服务,所谓启动就是执行这些服务的bootstrap函数 */ $this->bootstrap(); /* 这里会通过管线的方式来处理一个请求,获得处理结果,请求处理顺序如下: request->全局前置中间件->对应的路由中间件->对应的构造函数中间件->对应的controller的method->全局后置中间件->response */ return (new Pipeline($this->app)) ->send($request) ->through($this->app->shouldSkipMiddleware() ? [] : $this->middleware) ->then($this->dispatchToRouter()); }
该方法在$this->bootstrap()中启动的服务如下
//php会依次执行如下类中的bootstrap函数protected $bootstrappers = [ /* 加载环境变量,包括读取.env的内容 */ 'Illuminate\Foundation\Bootstrap\DetectEnvironment', /* 加载配置文件 */ 'Illuminate\Foundation\Bootstrap\LoadConfiguration', /* 配置日志 */ 'Illuminate\Foundation\Bootstrap\ConfigureLogging', /* 配置异常 */ 'Illuminate\Foundation\Bootstrap\HandleExceptions', /* 注册facade,读取config目录中app.aliases的内容,利用PHP的class_alias函数给相应的类设置对应的别名,为laravel的facade功能做准备 */ 'Illuminate\Foundation\Bootstrap\RegisterFacades', /* 注册服务,读取config目录下的app.providers中设置的服务提供者类,依次执行这些类实例的register函数来注册服务到服务容器中 */ 'Illuminate\Foundation\Bootstrap\RegisterProviders', /* 启动服务,针对刚才Illuminate\Foundation\Bootstrap\RegisterProviders获取到的服务提供者类,依次执行这些类的boot函数启动相应服务 */ 'Illuminate\Foundation\Bootstrap\BootProviders', ];
推荐阅读