美文网首页
Laravel5工作流程分析

Laravel5工作流程分析

作者: bluemap | 来源:发表于2018-05-01 22:34 被阅读0次

    初学Laravel难免对项目组织结构、工作流程不太了解,本文以尽量简单的方式向大家做大概介绍。

    组织结构说明

    成功创建Laravel后,项目组织结构如下图所示。

    组织结构

    运行效果

    合理配置web服务器后运行,正常运行效果如下。

    运行效果

    启动流程分析

    Laravel是如何展示上面网页的呢,下面我们来慢慢揭晓。
    下图为我简单整理的启动流程序列图,估计不太清晰,建议大家下载原图查看。


    laravel工作流程
    备注:为了图片简单,上面序列图中,大部分函数调用的返回箭头我是省略掉了,相信略有基础的人应该都可以看懂。
    

    一、创建App对象

    在Laravel中一个app对象就是一个Container(服务容器,概念不清晰的推荐阅读科普好文官方介绍),这就意味着app可以绑定各类Provider(服务提供者)
    public/index.php是程序入口,public/index.php中通过如下代码创建一个app对象。

    $app = require_once __DIR__.'/../bootstrap/app.php';
    

    进入bootstrap/app.php文件,我们看到如下代码,该代码创建了一个Application对象实例。

    $app = new Illuminate\Foundation\Application(
        realpath(__DIR__.'/../')
    );
    

    进入Application源文件,我们可以看到这样的类定义:

    class Application extends Container implements ApplicationContract, HttpKernelInterface
    

    可以看出来Application就是一个Container,同时Application也继承了ApplicationContract及HttpKernelInterface接口。
    再深入一点,我们可以看到ApplicationContract主要定义了一组获取项目路径、环境信息、Provider(服务提供者)的接口,及程序启动相关的boot()、booted()等接口。而HttpKernelInterface主要定义了http相关的事件处理接口handle()。

    二、绑定服务

    我们继续阅读bootstrap/app.php文件,可以看到如下代码

    //注册一个App\Http\Kernel服务Class,这个类主要用于http相关事件处理
    $app->singleton(
        Illuminate\Contracts\Http\Kernel::class,
        App\Http\Kernel::class
    );
    //注册一个App\Console\Kernel服务Class,这里我还不太清楚该类的作用
    $app->singleton(
        Illuminate\Contracts\Console\Kernel::class,
        App\Console\Kernel::class
    );
    //注册异常处理Handler,没深入去研究,看代码基本上是接受到异常后还是交给父类处理
    $app->singleton(
        Illuminate\Contracts\Debug\ExceptionHandler::class,
        App\Exceptions\Handler::class
    );
    

    上面代码中很关键的一个点是注册App\Http\Kernel,从上面流程图你可以大致感觉到这个类的重要性。

    如果你困惑为什么注册的函数名叫singleton,建议你看看函数内部实现,其实内部就是调用的Container->bind()方法,只是对外换了个名字而已。
    

    通常,绑定并不会实例化对象,绑定可以简单理解为通过一个字典将interface跟具体的class(或匿名函数Closure)关联起来,其中字典的key就是interface的名字,字典的value就是class名字,理解这一点非常重要,因为这是Container实现di(dependency injection依赖注入)和ioc(Inversion Of Control控制反转)很重要的一环。

    三、实例化各类服务及路由处理

    回到public/index.php,我们看到如下代码。

    //实例化一个kernel对象。
    $kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);
    
    $response = $kernel->handle(
        $request = Illuminate\Http\Request::capture()
    );
    

    上面代码中app->make才是真正将App\Http\Kernel对象实例化。怎么实例化的呢?前面我们有讲到,绑定就是将interface名跟与之对应的class存入一个字典中,而make就是通过interface名找到对应的class名,并用反射机制创建对应的class实例。
    kernel->handle()传入一个request并返回一个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());
        }
    

    其中bootstrap()接口会调用app相关方法来实例化LoadConfiguration、BootProviders、RegisterProviders等对象。
    app对象通过读取config/app.php配置文件来设置App\Providers\RouteServiceProvider、
    App\Providers\AppServiceProvider等。

       'providers' => [
            //是的,为了简洁,这里我删除了一些系统默认provider,大家可以去查阅源码
            /*
             * Application Service Providers...
             */
            App\Providers\AppServiceProvider::class,
            App\Providers\AuthServiceProvider::class,
            // App\Providers\BroadcastServiceProvider::class,
            App\Providers\EventServiceProvider::class,
            App\Providers\RouteServiceProvider::class,
    
        ],
    

    获取完配置信息之后app会初始化一个App\Providers\RouteServiceProvider对象,并调用其boot()方法,boot()最终会设置好程序的路由映射关系。
    RouteServiceProvider是很重要的一个类,我们看下路由映射关系代码。

        protected function mapWebRoutes()
        {
            Route::middleware('web')
                 ->namespace($this->namespace)
                 ->group(base_path('routes/web.php'));
        }
    
        /**
         * Define the "api" routes for the application.
         *
         * These routes are typically stateless.
         *
         * @return void
         */
        protected function mapApiRoutes()
        {
            Route::prefix('api')
                 ->middleware('api')
                 ->namespace($this->namespace)
                 ->group(base_path('routes/api.php'));
        }
    

    通过代码我们发现,web接口对应的路由配置文件是routes/web.php。
    打开routes/web.php,我们可以看到如下代码。

    Route::get('/', function () {
        return view('welcome');
    });
    

    从代码我们大致能够猜测,当用户访问网站首页的时候将返回一个'welcome'页面,而这个页面实际上就是resources/views/welcome.blade.php。我们可以debug一下view(),其内部有一组规则将'welcome'映射到welcome.blade.php文件。
    设置好路由之后kernel对象会调用dispatchToRouter(),并最终生成一个response对象,response对象里面包含welcome.blade.php返回的网页数据。

    输出内容

    在回到public/index.php,下面的事情就变得简单。

    //将页面内容输出到调用者(这里指浏览器)
    $response->send();
    //扫尾工作
    $kernel->terminate($request, $response);
    

    以上是Laravel工作流程的分析,如果感觉还是不太理解,建议认真阅读Laravel中文手册
    同时也推荐大家看看如下推荐文章,不同的作者有不同的介绍方式,个人感悟也可能不一样。
    https://www.jianshu.com/p/509a8dd5654e
    https://www.jianshu.com/p/63a3d76e7aca

    相关文章

      网友评论

          本文标题:Laravel5工作流程分析

          本文链接:https://www.haomeiwen.com/subject/vnrxrftx.html