Laravel5.x启动过程分析

来源:互联网 发布:淘宝装修免费一键安装 编辑:程序博客网 时间:2024/06/05 06:19

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);
0 0