Laravel5.3 流程粗粒度分析之bootstrap
从laravel入口文件index里面外面不难定位到Illuminate\Foundation\Http\Kernel的handle方法,同样也不难发现handle方法的核心是
$response = $this->sendRequestThroughRouter($request);
继续跟踪这个方法
/**
* Send the given request through the middleware / router.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\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());
}
今天我们要讨论的就是方法中的$this->bootstrap();
/**
* Bootstrap the application for HTTP requests.
*
* @return void
*/
public function bootstrap()
{
if (! $this->app->hasBeenBootstrapped()) {
$this->app->bootstrapWith($this->bootstrappers());
}
}
首先,我们先确定这个方法中的$this->app是类Illuminate\Foundation\Application以及$this->bootstrappers()如下所示数组
protected $bootstrappers = [
'Illuminate\Foundation\Bootstrap\DetectEnvironment',
'Illuminate\Foundation\Bootstrap\LoadConfiguration',
'Illuminate\Foundation\Bootstrap\ConfigureLogging',
'Illuminate\Foundation\Bootstrap\HandleExceptions',
'Illuminate\Foundation\Bootstrap\RegisterFacades',
'Illuminate\Foundation\Bootstrap\RegisterProviders',
'Illuminate\Foundation\Bootstrap\BootProviders',
];
那么接下来我们查看$this->app->bootstrapWith($this->bootstrappers())
/**
* Run the given array of bootstrap classes.
*
* @param array $bootstrappers
* @return void
*/
public function bootstrapWith(array $bootstrappers)
{
$this->hasBeenBootstrapped = true;
foreach ($bootstrappers as $bootstrapper) {
$this['events']->fire('bootstrapping: '.$bootstrapper, [$this]);
$this->make($bootstrapper)->bootstrap($this);
$this['events']->fire('bootstrapped: '.$bootstrapper, [$this]);
}
}
因为是粗粒度分析,我们同样只看这个方法的核心$this->make($bootstrapper)->bootstrap($this),$this->make($bootstrapper)这个我们简单的理解为new $bootstrapper即可,所以这句代码的意思就是将上面$bootstrappers数组里面的每个类实例化并调用他们的bootstrap方法,那么上面那些类都是干什么的呢,其实从类的名字也可以猜出大概的意思了。
Illuminate\Foundation\Bootstrap\DetectEnvironment::bootstrap,从名字看,像是检查环境,具体代码如下:
/**
* Bootstrap the given application.
*
* @param \Illuminate\Contracts\Foundation\Application $app
* @return void
*/
public function bootstrap(Application $app)
{
if (! $app->configurationIsCached()) {
$this->checkForSpecificEnvironmentFile($app);
try {
//$app->environmentPath()默认是我们的basePath,$app->environmentFile()默认是根目录里面的.env文件
(new Dotenv($app->environmentPath(), $app->environmentFile()))->load();
} catch (InvalidPathException $e) {
//
}
}
}
Illuminate\Foundation\Bootstrap\LoadConfiguration::bootstrap从名字看,像是加载配置,代码如下
/**
* Bootstrap the given application.
*
* @param \Illuminate\Contracts\Foundation\Application $app
* @return void
*/
public function bootstrap(Application $app)
{
$items = [];
// First we will see if we have a cache configuration file. If we do, we'll load
// the configuration items from that file so that it is very quick. Otherwise
// we will need to spin through every configuration file and load them all.
if (file_exists($cached = $app->getCachedConfigPath())) {
$items = require $cached;
$loadedFromCache = true;
}
$app->instance('config', $config = new Repository($items));
// Next we will spin through all of the configuration files in the configuration
// directory and load each one into the repository. This will make all of the
// options available to the developer for use in various parts of this app.
if (! isset($loadedFromCache)) {
$this->loadConfigurationFiles($app, $config);
}
$app->detectEnvironment(function () use ($config) {
return $config->get('app.env', 'production');
});
date_default_timezone_set($config['app.timezone']);
mb_internal_encoding('UTF-8');
}
Illuminate\Foundation\Bootstrap\ConfigureLogging::bootstrap从名字看,像是配置日志,代码如下
/**
* Bootstrap the given application.
*
* @param \Illuminate\Contracts\Foundation\Application $app
* @return void
*/
public function bootstrap(Application $app)
{
//大概就是默认使用Monolog作为日志记录
$log = $this->registerLogger($app);
// If a custom Monolog configurator has been registered for the application
// we will call that, passing Monolog along. Otherwise, we will grab the
// the configurations for the log system and use it for configuration.
if ($app->hasMonologConfigurator()) {
call_user_func(
$app->getMonologConfigurator(), $log->getMonolog()
);
} else {
$this->configureHandlers($app, $log);
}
}
/**
* Register the logger instance in the container.
*
* @param \Illuminate\Contracts\Foundation\Application $app
* @return \Illuminate\Log\Writer
*/
protected function registerLogger(Application $app)
{
$app->instance('log', $log = new Writer(
new Monolog($app->environment()), $app['events'])
);
return $log;
}
Illuminate\Foundation\Bootstrap\HandleExceptions::bootstrap看名字,像是处理异常,代码如下
/**
* Bootstrap the given application.
*
* @param \Illuminate\Contracts\Foundation\Application $app
* @return void
*/
public function bootstrap(Application $app)
{
$this->app = $app;
error_reporting(-1);
set_error_handler([$this, 'handleError']);
set_exception_handler([$this, 'handleException']);
register_shutdown_function([$this, 'handleShutdown']);
if (! $app->environment('testing')) {
ini_set('display_errors', 'Off');
}
}
Illuminate\Foundation\Bootstrap\RegisterFacades::bootstrap看名字像是注册Facades,代码如下,config目录下app配置的aliases配置就是在这里加载的
/**
* Bootstrap the given application.
*
* @param \Illuminate\Contracts\Foundation\Application $app
* @return void
*/
public function bootstrap(Application $app)
{
Facade::clearResolvedInstances();
Facade::setFacadeApplication($app);
AliasLoader::getInstance($app->make('config')->get('app.aliases', []))->register();
}
Illuminate\Foundation\Bootstrap\RegisterProviders::bootstrap看名字像是注册Providers,代码如下,config目录下app配置的providers配置就是在这里注册的
/**
* Bootstrap the given application.
*
* @param \Illuminate\Contracts\Foundation\Application $app
* @return void
*/
public function bootstrap(Application $app)
{
$app->registerConfiguredProviders();
}
Illuminate\Foundation\Bootstrap\BootProviders::bootstrap看名字像是启动Providers,代码如下,其实就是执行上面注册的Providers数组中各个Provide的boot方法
/**
* Bootstrap the given application.
*
* @param \Illuminate\Contracts\Foundation\Application $app
* @return void
*/
public function bootstrap(Application $app)
{
$app->boot();
}
/**
* Boot the application's service providers.
*
* @return void
*/
public function boot()
{
if ($this->booted) {
return;
}
// Once the application has booted we will also fire some "booted" callbacks
// for any listeners that need to do work after this initial booting gets
// finished. This is useful when ordering the boot-up processes we run.
$this->fireAppCallbacks($this->bootingCallbacks);
array_walk($this->serviceProviders, function ($p) {
$this->bootProvider($p);
});
$this->booted = true;
$this->fireAppCallbacks($this->bootedCallbacks);
}
我们经常安装一个扩展功能的时候需要去config里面的app.php的providers和aliases里面添加一些东西,通过以上的大概流程分析,我们就知道laravel是怎么处理这些东西的。