Laravel5.x启动过程分析

本文深入剖析了Laravel5.x的启动过程,从初始化Application开始,详细讲解了注册基本绑定和服务提供者,如EventServiceProvider和RoutingServiceProvider,以及核心类别名的设置。接着,介绍了注册共享的Kernel和异常处理器,处理请求和响应的关键步骤,包括make方法的调用、Kernel的构建以及中间件的执行,最后解释了如何处理web请求并结束应用生命周期。
摘要由CSDN通过智能技术生成

1、初始化Application

// realpath(__DIR__.'/../') 为web应用目录
// 如 D:\www\laravel5.1\
$app = new Illuminate\Foundation\Application(
    realpath(__DIR__.'/../')
);

接下来调用 Application类的构造方法

    /**
     * Create a new Illuminate application instance.
     *
     * @param  string|null  $basePath
     * @return void
     */
    public function __construct($basePath = null)
    {   
        // 注册基本绑定 这一步主要是把app和Illuminate\Container\Container指向Application实例,并添加到instances属性里
        $this->registerBaseBindings();
        // 注册基本服务提供者,添加到bindings属性里
        $this->registerBaseServiceProviders();
        // 注册核心类的别名, 添加到aliases属性里
        $this->registerCoreContainerAliases();
    // 设置根路径,添加到instances属性里
        if ($basePath) {
            $this->setBasePath($basePath);
        }
    }

1.1 注册基本绑定

    /**
     * Register the basic bindings into the container.
     *
     * @return void
     */
    protected function registerBaseBindings()
    {
        // $this Application实例
        static::setInstance($this);
        // app指向Illuminate\Foundation\Application实例
        $this->instance('app', $this);
        // Illuminate\Container\Container指向Illuminate\Foundation\Application实例
        $this->instance('Illuminate\Container\Container', $this);
        //dd($this->instances);
    }

输出$this->instances结果为:

array:2 [▼
  "app" => Application {#2 ▶}
  "Illuminate\Container\Container" => Application {#2 ▶}
]

1.2 注册基本服务提供者

    /**
     * Register all of the base service providers.
     *
     * @return void
     */
    protected function registerBaseServiceProviders()
    { 
      // 注册事件服务提供者        
      $this->register(new EventServiceProvider($this));
      // 注册路由服务提供者  
      $this->register(new RoutingServiceProvider($this));
    }

EventServiceProvider 继承 Illuminate\Support\ServiceProvider类,实例化时会先调用ServiceProvider的构造方法

    /**
     * Create a new service provider instance.
     *
     * @param  \Illuminate\Contracts\Foundation\Application  $app
     * @return void
     */
    public function __construct($app)
    {   // 将Application实例赋值给当前对象的成员变量
        $this->app = $app;
    }

register方法

   /**
     * Register a service provider with the application.
     *
     * @param  \Illuminate\Support\ServiceProvider|string  $provider
     * @param  array  $options
     * @param  bool   $force
     * @return \Illuminate\Support\ServiceProvider
     */
    public function register($provider, $options = [], $force = false)
    {   

        if ($registered = $this->getProvider($provider) && ! $force) {

            return $registered;
        }

        // If the given "provider" is a string, we will resolve it, passing in the
        // application instance automatically for the developer. This is simply
        // a more convenient way of specifying your service provider classes.
        if (is_string($provider)) {
            $provider = $this->resolveProviderClass($provider);
        }

    // 这里调用的是EventServiceProvider类的register方法
        $provider->register();

        // Once we have registered the service we will iterate through the options
        // and set each of them on the application so they will be available on
        // the actual loading of the service objects and for developer usage.
        foreach ($options as $key => $value) {
            $this[$key] = $value;
        }

        $this->markAsRegistered($provider);

        // If the application has already booted, we will call this boot method on
        // the provider class so it has an opportunity to do its boot logic and
        // will be ready for any usage by the developer's application logics.
        if ($this->booted) {
            $this->bootProvider($provider);
        }

        return $provider;
    }

EventServiceProvider类的register方法

    /**
     * Register the service provider.
     *
     * @return void
     */
    public function register()
    {   
        // 调用Application实例的singleton方法,该方法继承自
        // Illuminate\Container\Container.php
        $this->app->singleton('events', function ($app) {
            return (new Dispatcher($app))->setQueueResolver(function () use ($app) {
                return $app->make('Illuminate\Contracts\Queue\Factory');
            });
        });
    }

 /**
     * Register a shared binding in the container.
     *
     * @param  string|array  $abstract
     * @param  \Closure|string|null  $concrete
     * @return void
     */
    public function singleton($abstract, $concrete = null)
    {   // 注册绑定
        $this->bind($abstract, $concrete, true);
    }

在bind方法中将event添加到 binding中

$this->bindings[$abstract] = compact('concrete', 'shared');

这时输出$this->bindings结果如下

array:1 [▼
  "events" => array:2 [▼
    "concrete" => Closure {#4 ▶}
    "shared" => true
  ]
]

markAsRegistered方法

    /**
     * Mark the given provider as registered.
     *
     * @param  \Illuminate\Support\ServiceProvider  $provider
     * @return void
     */
    protected function markAsRegistered($provider)
    {   
        // 这里要特别主要 $this['events'],调用的是数组中不存在的key
        $this['events']->fire($class = get_class($provider), [$provider]);
        $this->serviceProviders[] = $provider;

        $this->loadedProviders[$class] = true;

    }

注:因为该类实现了 ArrayAccess接口,当调用数组中不存在的key时,会调用 ArrayAccess::offsetGet 方法(具体自行参考PHP参考文档ArrayAccess),这个方法在Illuminate\Container\Container.php中实现

    /**
     * Get the value at a given offset.
     *
     * @param  string  $key
     * @return mixed
     */
    public function offsetGet($key)
    { 
        return $this->make($key);
    }

接下来的部分是RoutingServiceProvider

    /**
     * Register the service provider.
     *
     * @return void
     */
    public function register()
    {   
        $this->registerRouter();

        $this->registerUrlGenerator();

        $this->registerRedirector();

        $this->registerPsrRequest();

        $this->registerPsrResponse();

        $this->registerResponseFactory();
        //dd($this->app);
    }

这部分的目的主要是绑定关系,从输出结果我们可以明显看出

Application {#2 ▼
  #basePath: null
  #hasBeenBootstrapped: false
  #booted: false
  #bootingCallbacks: []
  #bootedCallbacks: []
  #terminatingCallbacks: []
  #serviceProviders: array:1 [▶]
  #loadedProviders: array:1 [▶]
  #deferredServices: []
  #monologConfigurator: null
  #databasePath: null
  #storagePath: null
  #environmentPath: null
  #environmentFile: ".env"
  #namespace: null
  #resolved: array:1 [▶]
  #bindings: array:7 [▼
    "events" => array:2 [▶]
    "router" => array:2 [▶]
    "url" => array:2 [▶]
    "redirect" => array:2 [▶]
    "Psr\Http\Message\ServerRequestInterface" => array:2 [▶]
    "Psr\Http\Message\ResponseInterface" => array:2 [▶]
    "Illuminate\Contracts\Routing\ResponseFactory" => array:2 [▶]
  ]

注:在调用registerRouter方法时,也就是下面这段代码

    /**
     * Register the router instance.
     *
     * @return void
     */
    protected function registerRouter()
    {   
        // 这里是一个赋值操作,因为实现了ArrayAccess接口,如果$this->app['router']不存在,则会调用ArrayAccess::offsetSet方法,也就是(Illuminate\Container\Container.php里的offsetSet方法)。
        $this->app['router'] = $this->app->share(function ($app) {
            return new Router($app['events'], $app);
        });
    }

1.3 注册核心类别名
通过输出$this->app得到以下结果,在aliases数组中可以看到对应关系

Application {#2 ▼
  #basePath: null
  #hasBeenBootstrapped: false
  #booted: false
  #bootingCallbacks: []
  #bootedCallbacks: []
  #terminatingCallbacks: []
  #serviceProviders: array:2 [▶]
  #loadedProviders: array:2 [▶]
  #deferredServices: []
  #monologConfigurator: null
  #databasePath: null
  #storagePath: null
  #environmentPath: null
  #environmentFile: ".env"
  #namespace: null
  #resolved: array:1 [▶]
  #bindings: array:7 [▶]
  #instances: array:3 [▶]
  #aliases: array:59 [▼
    "Illuminate\Foundation\Application" => "app"
    "Illuminate\Contracts\Container\Container" => "app"
    "Illuminate\Contracts\Foundation\Application" => "app"
    "Illuminate\Auth\AuthManager" => "auth"
    "Illuminate\Auth\Guard" => "auth.driver"
    "Illuminate\Contracts\Auth\Guard" => "auth.driver"
    "Illuminate\Auth\Passwords\TokenRepositoryInterface" => "auth.password.tokens"
    "Illuminate\View\Compilers\BladeCompiler" => "blade.compiler"
    "Illuminate\Cache\CacheManager" => "cache"
    "Illuminate\Contracts\Cache\Factory" => "cache"
    "Illuminate\Cache\Repository" => "cache.store"
    "Illuminate\Contracts\Cache\Repository" => "cache.store"
    "Illuminate\Config\Repository" => "config"
    "Illuminate\Contracts\Config\Repository" => "config"
    "Illuminate\Cookie\CookieJar" => "cookie"
    "Illuminate\Contracts\Cookie\Factory" => "cookie"
    "Illuminate\Contracts\Cookie\QueueingFactory" => "cookie"
    "Illuminate\Encryption\Encrypter" => "encrypter"
    "Illuminate\Contracts\Encryption\Encrypter" => "encrypter"
    "Illuminate\Database\DatabaseManager" => "db"
    "Illuminate\Database\Connection" => "db.connection"
    "Illuminate\Database\ConnectionInterface" => "db.connection"
    "Illuminate\Events\Dispatcher" => "events"
    "Illuminate\Contracts\Events\Dispatcher" => "events"
    "Illuminate\Filesystem\Filesystem" => "files"
    "Illuminate\Filesystem\FilesystemManager" => "filesystem"
    "Illuminate\Contracts\Filesystem\Factory" => "filesystem"
    "Illuminate\Contracts\Filesystem\Filesystem" => "filesystem.disk"
    "Illuminate\Contracts\Filesystem\Cloud" => "filesystem.cloud"
    "Illuminate\Contracts\Hashing\Hasher" => "hash"
    "Illuminate\Translation\Translator" => "translator"
    "Symfony\Component\Translation\TranslatorInterface" => "translator"
    "Illuminate\Log\Writer" => "log"
    "Illuminate\Contracts\Logging\Log" => "log"
    "Psr\Log\LoggerInterface" => "log"
    "Illuminate\Mail\Mailer" => "mailer"
    "Illuminate\Contracts\Mail\Mailer" => "mailer"
    "Illuminate\Contracts\Mail\MailQueue" => "mailer"
    "Illuminate\Auth\Passwords\PasswordBroker" => "auth.password"
    "Illuminate\Contracts\Auth\PasswordBroker" => "auth.password"
    "Illuminate\Queue\QueueManager" => "queue"
    "Illuminate\Contracts\Queue\Factory" => "queue"
    "Illuminate\Contracts\Queue\Monitor" => "queue"
    "Illuminate\Contracts\Queue\Queue" => "queue.connection"
    "Illuminate\Routing\Redirector" => "redirect"
    "Illuminate\Redis\Database" => "redis"
    "Illuminate\Contracts\Redis\Database" => "redis"
    "Illuminate\Http\Request" => "request"
    "Illuminate\Routing\Router" => "router"
    "Illuminate\Contracts\Routing\Registrar" => "router"
    "Illuminate\Session\SessionManager" => "session"
    "Illuminate\Session\Store" => "session.store"
    "Symfony\Component\HttpFoundation\Session\SessionInterface" => "session.store"
    "Illuminate\Routing\UrlGenerator" => "url"
    "Illuminate\Contracts\Routing\UrlGenerator" => "url"
    "Illuminate\Validation\Factory" => "validator"
    "Illuminate\Contracts\Validation\Factory" => "validator"
    "Illuminate\View\Factory" => "view"
    "Illuminate\Contracts\View\Factory" => "view"
  ]

1.4 设置根路径

  #instances: array:10 [▼
    "app" => Application {#2}
    "Illuminate\Container\Container" => Application {#2}
    "events" => Dispatcher {#5 ▶}
    "path" => "D:\www\laravel5.1\app"
    "path.base" => "D:\www\laravel5.1"
    "path.config" => "D:\www\laravel5.1\config"
    "path.database" => "D:\www\laravel5.1\database"
    "path.lang" => "D:\www\laravel5.1\resources\lang"
    "path.public" => "D:\www\laravel5.1\public"
    "path.storage" => "D:\www\laravel5.1\storage"
  ]

2、注册共享的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
);

上述代码将绑定关系添加到bindings属性里,里面的::class 是php新增的静态属性

  #bindings: array:10 [▼
    "events" => array:2 [▶]
    "router" => array:2 [▶]
    "url" => array:2 [▶]
    "redirect" => array:2 [▶]
    "Psr\Http\Message\ServerRequestInterface" => array:2 [▶]
    "Psr\Http\Message\ResponseInterface" => array:2 [▶]
    "Illuminate\Contracts\Routing\ResponseFactory" => array:2 [▶]
    "Illuminate\Contracts\Http\Kernel" => array:2 [▶]
    "Illuminate\Contracts\Console\Kernel" => array:2 [▶]
    "Illuminate\Contracts\Debug\ExceptionHandler" => array:2 [▶]
  ]

3、处理请求和响应
这时我们获取$app后返回index.php页面,然后执行

$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);

这里要注意,make方法调用的是子类Illuminate\Foundation\Application.php里的方法,然后在调用父类Illuminate\Container\Container.php的make方法

接着是make方法里的

// 这里返回bindings数组里的数据,因为我们在获取$app的时候已经把
// "Illuminate\Contracts\Http\Kernel"绑定了
$concrete = $this->getConcrete($abstract);

接着我们调用$object = $this->build($concrete, $parameters);
这build方法中

        if ($concrete instanceof Closure) {
            return $concrete($this, $parameters);
        }

因为$concrete是闭包,所以直接返回,这里调用的是我们绑定在app里的闭包也就是,

“Illuminate\Contracts\Http\Kernel” => array:2 [▼
“concrete” => Closure {#23 ▼
class: “Illuminate\Container\Container”
this: Application {#2}
parameters: array:2 [▶]
use: array:2 [▼
“$abstract” => “Illuminate\Contracts\Http\Kernel”
“$concrete” => “App\Http\Kernel”
]
file: “D:\www\laravel5.1\vendor\laravel\framework\src\Illuminate\Container\Container.php”
line: “222 to 226”
}
“shared” => true
]

执行这个方法 concrete( this, $parameters)的时候也就是调用Illuminate\Container\Container.php第222到226行之间的代码,传递的参数就是上述use中黑色斜线部分标注的,

function ($c, $parameters = []) use ($abstract, $concrete) {
            // 根据上述use中的参数,这里赋值应该是make
            $method = ($abstract == $concrete) ? 'build' : 'make';
    // 然后在调用application.php中的make方法,$concrete对应的就是App\Http\Kernel
            return $c->$method($concrete, $parameters);
        }

最终是调用构造函数设置 app/ router,初始化$router中middleware数值(定义在D:\www\laravel5.1\app\Http\Kernel.php文件中,这里我们可以添加任何自定义中间件)实例化App\Http\Kernel

Kernel {#24 ▼
  #middleware: array:6 [▼
    0 => "Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode"
    1 => "App\Http\Middleware\EncryptCookies"
    2 => "Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse"
    3 => "Illuminate\Session\Middleware\StartSession"
    4 => "Illuminate\View\Middleware\ShareErrorsFromSession"
    5 => "App\Http\Middleware\VerifyCsrfToken"
  ]
  #routeMiddleware: array:4 [▼
    "auth" => "App\Http\Middleware\Authenticate"
    "auth.basic" => "Illuminate\Auth\Middleware\AuthenticateWithBasicAuth"
    "guest" => "App\Http\Middleware\RedirectIfAuthenticated"
    "test" => "App\Http\Middleware\TestMiddleware"
  ]
  #app: Application {#2 ▶}
  #router: Router {#88 ▶}
  #bootstrappers: array:7 []
}

接下来是处理web请求的核心部分 handle方法

$response = $kernel->handle(
    // $request是经过Symfony封装的请求对象
    $request = Illuminate\Http\Request::capture()
);

调用bootstrap方法,启动一系列启动类的bootstrap(定义在\Illuminate\Foundation\Http\Kernel.php中)方法:

protected $bootstrappers = [
        // 该类用来读取.env定义的变量 环境配置($app[‘env’])
        'Illuminate\Foundation\Bootstrap\DetectEnvironment',
        // 扫描config文件下的所有.php结尾的配置文件 基本配置($app[‘config’])
        'Illuminate\Foundation\Bootstrap\LoadConfiguration',
        // 日志文件($app[‘log’])
        'Illuminate\Foundation\Bootstrap\ConfigureLogging',
        // 错误&异常处理
        'Illuminate\Foundation\Bootstrap\HandleExceptions',
        //清除已解析的Facade并重新启动,注册config文件中alias定义的所有Facade类到容器 (定义在配置文件app.php中的aliases数组)
       'Illuminate\Foundation\Bootstrap\RegisterFacades',
       //注册config中providers定义的所有Providers类到容器 (定义在配置文件app.php中的providers数组)
        'Illuminate\Foundation\Bootstrap\RegisterProviders',
        //调用所有已注册Providers的boot方法
        'Illuminate\Foundation\Bootstrap\BootProviders',
    ];

通过Pipeline发送请求,经过中间件,再由路由转发,最终返回响应

new Pipeline($this->app))
        ->send($request)
        ->through($this->middleware)
        ->then($this->dispatchToRouter()

将响应信息发送到浏览器:

$response->send();

处理继承自TerminableMiddleware接口的中间件(Session)并结束应用生命周期:

$kernel->terminate($request, $response);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值