美文网首页
一步步讲解laravel bootstrap启动过程,带你了解每

一步步讲解laravel bootstrap启动过程,带你了解每

作者: lifefruity | 来源:发表于2019-07-13 13:34 被阅读0次

背景:想知道web.php这个文件是如何被加载运行的

在sendRequestThroughRouter()中会启动一些类

public function bootstrap()
{
    if (! $this->app->hasBeenBootstrapped()) {
        $this->app->bootstrapWith($this->bootstrappers());
    }
}

public function bootstrapWith(array $bootstrappers)
{
    $this->hasBeenBootstrapped = true;
    /*
    $bootstrappers 打印出
    array(6) {
      [0]=>
      string(56) "Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables"
      [1]=>
      string(49) "Illuminate\Foundation\Bootstrap\LoadConfiguration"
      [2]=>
      string(48) "Illuminate\Foundation\Bootstrap\HandleExceptions"
      [3]=>
      string(47) "Illuminate\Foundation\Bootstrap\RegisterFacades"
      [4]=>
      string(49) "Illuminate\Foundation\Bootstrap\RegisterProviders"
      [5]=>
      string(45) "Illuminate\Foundation\Bootstrap\BootProviders"
    }
    */

    foreach ($bootstrappers as $bootstrapper) {
        $this['events']->dispatch('bootstrapping: '.$bootstrapper, [$this]);

        $this->make($bootstrapper)->bootstrap($this);

        $this['events']->dispatch('bootstrapped: '.$bootstrapper, [$this]);
    }
}

代码1

上面会运行6个类,这里举例了RegisterProviders的过程,也就是上面中的第5个

//在代码1中进行bootstrap,这里是Illuminate\Foundation\Bootstrap\RegisterProviders
public function bootstrap(Application $app)
{
    $app->registerConfiguredProviders();
}

//上面RegisterProviders的bootstrap中运行了如下方法
public function registerConfiguredProviders()
{
    //Illuminate里和app里的分开
    $providers = Collection::make($this->config['app.providers'])
                    ->partition(function ($provider) {
                        return Str::startsWith($provider, 'Illuminate\\');
                    });

    //添加一些其它的类文件
    $providers->splice(1, 0, [$this->make(PackageManifest::class)->providers()]);
    //所有的provider,真正去注册 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    (new ProviderRepository($this, new Filesystem, $this->getCachedServicesPath()))
                ->load($providers->collapse()->toArray());
}

//接上面最后一行Illuminate\Foundation\ProviderRepository.php
public function load(array $providers)
{
    //这里foreach的是很多的provider
    foreach ($manifest['eager'] as $provider) {
        $this->app->register($provider);//注册provider,运行每个provider的register方法
    }
}

到这里所有的provider register结束。

上面是Illuminate\Foundation\Bootstrap\RegisterProviders的运行过程
下面是Illuminate\Foundation\Bootstrap\BootProviders的运行过程,在代码1中,这个会最后运行
IIlluminate\Foundation\Bootstrap\BootProviders.php 对app进行了boot

//Illuminate\Foundation\Bootstrap\BootProviders.php
public function bootstrap(Application $app)
{
    $app->boot();
}

//Illuminate\Foundation\Application.php
public function boot()
{
    //对每个service provider进行bootProvider操作
    array_walk($this->serviceProviders, function ($p) {
        $this->bootProvider($p);
    });
}
//对每个provider进行boot操作
protected function bootProvider(ServiceProvider $provider)
{
    if (method_exists($provider, 'boot')) {
        return $this->call([$provider, 'boot']);
    }
}

会自动运行每个provider的boot方法,所以到了这里就能看RouteServiceProvider.php 中的boot方法到底做了什么,因为它也是provider中的一个。

分析route的boot方法,下面是来自不同文件的方法,为了看起来方便,把它们整合到了一起

public function boot()
{
    $this->loadRoutes();

    $this->app->booted(function () {
        $this->app['router']->getRoutes()->refreshNameLookups();
        $this->app['router']->getRoutes()->refreshActionLookups();
    });
}

protected function loadRoutes()
{
    if (method_exists($this, 'map')) {
        $this->app->call([$this, 'map']);
    }
}

public function map()
{
    $this->mapApiRoutes();
    $this->mapWebRoutes();
}

protected function mapWebRoutes()
{
    Route::middleware('jack route web');

    Route::middleware('web')
         ->namespace($this->namespace)
         ->group(base_path('routes/web.php'));
}

到这里就一步步分析了web.php是如何被加载的。也许会疑问group是什么作用,为什么web.php传进了这个group里,继续来研究。。。

其实在Route::middleware('web')是没有middleware这个静态方法的,所以调用的是Illuminate\Routing\Router.php中的__call 这个魔术方法,在这个__call里其实是new 的RouteRegistrar,所以到Illuminate\Routing\RouteRegistrar.php中找group方法。

public function group($callback)
{
    /*
     * array(2) {
          ["middleware"]=>
          array(1) {
            [0]=>
            string(3) "web"
          }
          ["namespace"]=>
          string(20) "App\Http\Controllers"
        }
        $callback就是group里传入的文件路径
     * */


    $this->router->group($this->attributes, $callback);
}

//Illuminate\Routing\Router.php
public function group(array $attributes, $routes)
{
    //放入到$this->groupStack中
    $this->updateGroupStack($attributes);

    $this->loadRoutes($routes);

    array_pop($this->groupStack);
}

protected function loadRoutes($routes)
{
    if ($routes instanceof Closure) {
        $routes($this);
    } else {
        //传入web.php的路径,D:\sites\laravel\routes\web.php
        (new RouteFileRegistrar($this))->register($routes);
    }
}

public function register($routes)
{
    $router = $this->router;

    require $routes;//这里就把web.php require进来了
}

到这里解释了web.php是如何被加载进来的 : )

相关文章

网友评论

      本文标题:一步步讲解laravel bootstrap启动过程,带你了解每

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