Laravel啓動執行關鍵流程

1、 laravel結構

|– app 包含Controller、Model、路由等在內的應用目錄,大部分業務將在該目錄下進行
    |  |– Console 命令行程序目錄
    |  |  |– Commands 包含了用於命令行執行的類,可在該目錄下自定義類
    |  |  |– Kernel.php 命令調用內核文件,包含commands變量(命令清單,自定義的命令需加入到這裏)和schedule方法(用於任務調度,即定時任務)
    |  |– Events 事件目錄
    |  |– Exceptions 包含了自定義錯誤和異常處理類
    |  |– Http HTTP傳輸層相關的類目錄
    |  |  |– Controllers 控制器目錄
    |  |  |– Middleware 中間件目錄
    |  |  |– Requests 請求類目錄
    |  |  |– Kernel.php 包含http中間件和路由中間件的內核文件
    |  |  |– routes.php 強大的路由
    |  |– Jobs 該目錄下包含隊列的任務類
    |  |– Listeners 監聽器目錄
    |  |– Providers 服務提供者目錄
    |  |– User.php 自帶的模型實例,咱們新建的Model默認也存儲在該目錄
    |– bootstrap 框架啓動載入目錄
    |  |– app.php 建立框架應用實例
    |  |– autoload.php 自動加載
    |  |– cache 存放框架啓動緩存,web服務器須要有該目錄的寫入權限
    |– config 各類配置文件的目錄
    |  |– app.php 系統級配置文件
    |  |– auth.php 用戶身份認證配置文件,指定好table和model就能夠很方便地用身份認證功能了
    |  |– broadcasting.php 事件廣播配置文件
    |  |– cache.php 緩存配置文件
    |  |– compile.php 編譯額外文件和類須要的配置文件,通常用戶不多用到
    |  |– database.php 數據庫配置文件
    |  |– filesystems.php 文件系統配置文件,這裏能夠配置雲存儲參數
    |  |– mail.php 電子郵件配置文件
    |  |– queue.php 消息隊列配置文件
    |  |– services.php 可存放第三方服務的配置信息
    |  |– session.php 配置session的存儲方式、生命週期等信息
    |  |– view.php 模板文件配置文件,包含模板目錄和編譯目錄等
    |– database 數據庫相關目錄
    |  |– factories 5.1以上版本的新特性,工廠類目錄,也是用於數據填充
    |  |  |– ModelFactory.php 在該文件可定義不一樣Model所需填充的數據類型
    |  |– migrations 存儲數據庫遷移文件
    |  |– seeds 存放數據填充類的目錄
    |     |– DatabaseSeeder.php 執行php artisan db:seed命令將會調用該類的run方法。該方法可調用執行該目錄下其餘Seeder類,也可調用factories方法生成ModelFactory裏定義的數據模型
    |– public 網站入口,應當將ip或域名指向該目錄而不是根目錄。可供外部訪問的css、js和圖片等資源皆放置於此
    |  |– index.php 入口文件
    |  |– .htaccess Apache服務器用該文件重寫URL
    |  |– web.config IIS服務器用該文件重寫URL
    |– resources 資源文件目錄
    |  |– assets 可存放包含LESS、SASS、CoffeeScript在內的原始資源文件
    |  |– lang 本地化文件目錄
    |  |– views 視圖文件就放在這啦
    |– storage 存儲目錄。web服務器須要有該目錄及全部子目錄的寫入權限
    |  |– app 可用於存儲應用程序所需的一些文件
    |  |– framework 該目錄下包括緩存、sessions和編譯後的視圖文件
    |  |– logs 日誌目錄
    |– tests 測試目錄
    |– vendor 該目錄下包含Laravel源代碼和第三方依賴包
    |– .env 環境配置文件。config目錄下的配置文件會使用該文件裏面的參數,不一樣生產環境使用不一樣的.env文件便可。
    |– artisan 強大的命令行接口,你能夠在app/Console/Commands下編寫自定義命令
    |– composer.json 存放依賴關係的文件
    |– composer.lock 鎖文件,存放安裝時依賴包的真實版本
    |– gulpfile.js gulp(一種前端構建工具)配置文件
    |– package.json gulp配置文件
    |– phpspec.yml phpspec(一種PHP測試框架)配置文件
    |– phpunit.xml phpunit(一種PHP測試框架)配置文件
    |– server.php PHP內置的Web服務器將把這個文件做爲入口。以public/index.php爲入口的能夠忽略掉該文件

2、啓動過程

index.php
bootstrap/autoload.php      --> 自動加載
bootstrap/app.php           --> 初始化服務容器(註冊基礎的服務提供者(事件、日誌、路由)、註冊核心類別名)
bootstrap/app.php           --> 註冊共享的Kernel和異常處理器
Foundation\Http\Kernel.php  --> 處理請求和響應
index.php                   --> 將響應信息發送到瀏覽器
index.php                   --> 處理繼承自TerminableMiddleware接口的中間件(Session)並結束應用生命週期

其中處理請求和響應包括:
    解析Illuminate\Contracts\Http\Kernel,實例化App\Http\Kernel
    a. 實例化Kernel : 構造函數:設置$app/$router,初始化$router中middleware數值
    b. handle處理請求:
        加載路由中間件、加載環境變量、加載配置文件、加載異常處理機制、註冊門面、註冊服務提供者、啓動服務提供者、管道模式注入中間件
    c.將響應信息發送到瀏覽器
        註冊request實例到容器 ($app['request']->Illuminate\Http\Request)  --  $request是通過Symfony封裝的請求對象
        清空以前容器中的request實例
        調用bootstrap方法,啓動一系列啓動類的bootstrap方法:
        Illuminate\Foundation\Bootstrap\DetectEnvironment  環境配置($app[‘env’])
        Illuminate\Foundation\Bootstrap\LoadConfiguration  基本配置($app[‘config’])
        Illuminate\Foundation\Bootstrap\ConfigureLogging   日誌文件($app[‘log’])
        Illuminate\Foundation\Bootstrap\HandleExceptions   錯誤&異常處理
        Illuminate\Foundation\Bootstrap\RegisterFacades    清除已解析的Facade並從新啓動,註冊config文件中alias定義的全部Facade類到容器
        Illuminate\Foundation\Bootstrap\RegisterProviders  註冊config中providers定義的全部Providers類到容器
        Illuminate\Foundation\Bootstrap\BootProviders      調用全部已註冊Providers的boot方法
        經過Pipeline發送請求,通過中間件,再由路由轉發,最終返回響應


1.自動加載
    包括全局函數的加載、頂級命名空間映射、PSR0、PSR4標準的實現

2.初始化服務容器
    註冊容器自己
        將基本的綁定註冊到容器中,包括容器自身、容器實例名稱app
        實例化
            app, Illuminate\Container\Container
        關鍵代碼:
            protected function registerBaseBindings() {
                static::setInstance($this);
                $this->instance('app', $this);
                $this->instance(Container::class, $this);
            }
    註冊基礎服務提供者
        向容器分別註冊了Key爲如下值得實例
            events
            log
            router、url、redirect、Illuminate\Contracts\Routing\ResponseFactory
        關鍵代碼:
            protected function registerBaseServiceProviders() {
                $this->register(new EventServiceProvider($this));
                $this->register(new LogServiceProvider($this));
                $this->register(new RoutingServiceProvider($this));
            }
    註冊容器別名(註冊共享的Kernel)
        在調用此方法以前,咱們想取得一個容器實例的作法是 App::make('app');
        如今咱們可使用三種方法來取得一個容器實例app
                    App::make('Illuminate\Foundation\Application')
                    App::make('Illuminate\Contracts\Container\Container')
                    App::make('Illuminate\Contracts\Foundation\Application')
        關鍵代碼:
            public function registerCoreContainerAliases(){
                ...
            }

3. 註冊共享的Kernel和異常處理器
        關鍵代碼:
            $app->singleton(
                Illuminate\Contracts\Http\Kernel::class,
                App\Http\Kernel::class
            );

            $app->singleton(
                Illuminate\Contracts\Console\Kernel::class,
                App\Console\Kernel::class
            );

            $app->singleton(
                Illuminate\Contracts\Debug\ExceptionHandler::class,
                App\Exceptions\Handler::class
            );

4. 處理請求和響應
        實例化App\Http\Kernel
        構造函數:設置$app/$router,初始化$router中middleware數值
        關鍵代碼:
                public function __construct(Application $app, Router $router)
                {
                    $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);
                    }
                }

5. handle處理請求
        a. 註冊request實例到容器 ($app['request']->Illuminate\Http\Request)  --  $request是通過Symfony封裝的請求對象
        b. 清空以前容器中的request實例
        c. 調用bootstrap方法,啓動一系列啓動類的bootstrap方法
        d. 經過Pipeline發送請求,通過中間件,再由路由轉發,最終返回響應

        關鍵代碼:
            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());
            }


6. bootstrap方法
        a.檢測環境變量文件是否正常
        b.取得配置文件,即把/config/下的全部配置文件讀取到容器(app()->make('config')能夠查看全部配置信息)
        c.註冊異常: set_error_handler,set_exception_handler, register_shutdown_function
        d.把/config/app.php裏面的aliases項利用PHP庫函數class_alias建立別名,今後,咱們可使用App::make('app')方式取得實例
        e.把/config/app.php裏面的providers項,註冊到容器
        f.運行容器中註冊的全部的ServiceProvider中得boot方法

        關鍵代碼:
            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,
            ];

7. 將響應信息發送到瀏覽器
        關鍵代碼:
            $response->send();


9. 處理繼承自TerminableMiddleware
        關鍵代碼:
            $kernel->terminate($request, $response);


10. Laravel路由
    $this->dispatchToRouter()
    --> $this->router->dispatch($request)
    --> $this->dispatchToRoute($request);  -- /Illuminate/Routing/Router.php
    --> $response = $this->runRouteWithinStack($route, $request);

    //乾貨來了
    protected function runRouteWithinStack(Route $route, Request $request)
    {
        // 取得routes.php裏面的Middleware節點
        $middleware = $this->gatherRouteMiddlewares($route);
        //這個有點眼熟
        return (new Pipeline($this->container))
                ->send($request)
                ->through($middleware)    //執行上述的中間件
                ->then(function($request) use ($route)
                {
                    //不容易啊,終於到Controller類了
                    return $this->prepareResponse(
                        $request,
                        $route->run($request); //run控制器
                    );
                });
    }
相關文章
相關標籤/搜索