Laravel 配置项即时载入的服务提供者 (根目录:/var/www/laravel/)
所有即时载入的服务注册完成之后,会立即调用 register 方法,并标记为已载入。
随后通过 \Illuminate\Foundation\Bootstrap\BootProviders 启动项来调用所有的即时加载服务提供者的 boot 方法
查看根据 config/app.php 中的 providers 生成的 bootstrap/cache/services.php
'eager' =>
array (
// 系统服务提供者
0 => 'Illuminate\\Auth\\AuthServiceProvider', // 注入验证相关对象
1 => 'Illuminate\\Cookie\\CookieServiceProvider', // 注入cookie对象
2 => 'Illuminate\\Database\\DatabaseServiceProvider', // 注入db相关对象
3 => 'Illuminate\\Encryption\\EncryptionServiceProvider', // 注入加解密对象
4 => 'Illuminate\\Filesystem\\FilesystemServiceProvider', // 注入文件相关对象
5 => 'Illuminate\\Foundation\\Providers\\FoundationServiceProvider',// 注入基础的请求对象
6 => 'Illuminate\\Notifications\\NotificationServiceProvider', // 注入通知对象
7 => 'Illuminate\\Pagination\\PaginationServiceProvider', // 注入分页相关对象
8 => 'Illuminate\\Session\\SessionServiceProvider', // 注入session相关对象
9 => 'Illuminate\\View\\ViewServiceProvider', // 注入视图相关对象
10 => 'Laravel\\Passport\\PassportServiceProvider', // 注入passport相关对象
// 配置项服务提供者
11 => 'App\\Providers\\AppServiceProvider',
12 => 'App\\Providers\\AuthServiceProvider',
13 => 'App\\Providers\\EventServiceProvider',
14 => 'App\\Providers\\RouteServiceProvider',
)
路由相关服务提供者
// 主要是注册完之后的 boot 方法调用
App\\Providers\\RouteServiceProvider
public function boot()
{
// 可以加入自己的操作
parent::boot();
}
public function boot()
{
$this->setRootControllerNamespace();
// 若执行了 php artisan routes:cache(自动生成路由缓存文件,注意:建议只在项目上线时操作),直接加载
if ($this->app->routesAreCached()) {
$this->loadCachedRoutes();
} else {
// 加载路由
$this->loadRoutes();
// 设置系统启动时的事件监听函数
$this->app->booted(function () {
$this->app['router']->getRoutes()->refreshNameLookups();
});
}
}
protected function setRootControllerNamespace()
{
if (! is_null($this->namespace)) {
// 设置 $this->instances['url'] (\Illuminate\Routing\UrlGenerator对象)的 rootNamespace 属性
$this->app[UrlGenerator::class]->setRootControllerNamespace($this->namespace);
}
}
public function routesAreCached()
{
return $this['files']->exists($this->getCachedRoutesPath());
}
public function getCachedRoutesPath()
{
return $this->bootstrapPath().'/cache/routes.php';
}
protected function loadRoutes()
{
if (method_exists($this, 'map')) {
$this->app->call([$this, 'map']);
}
}
public function map()
{
$this->mapApiRoutes();
$this->mapWebRoutes();
}
// API 相关的路由
protected function mapApiRoutes()
{
Route::prefix('api')
->middleware('api')
->namespace($this->namespace)
->group(base_path('routes/api.php'));
}
// WEB 相关的路由
protected function mapWebRoutes()
{
Route::middleware('web')
->namespace($this->namespace)
->group(base_path('routes/web.php'));
}
public function booted($callback)
{
$this->bootedCallbacks[] = $callback;
// 如果应用已经启动了,则直接调用
if ($this->isBooted()) {
$this->fireAppCallbacks([$callback]);
}
}
// Route 是 Facde 的调用方式
分析: Route::middleware('web')
->namespace($this->namespace)
->group(base_path('routes/web.php'));
Route::middleware
public static function __callStatic($method, $args)
{
// 获取应用的 router 对象
$instance = static::getFacadeRoot();
if (! $instance) {
throw new RuntimeException('A facade root has not been set.');
}
// 将 Router::middleware() 转化为应用的 Router->middleware() 方式,若 Router 没有 middleware 方法,则直接触发 __call
return $instance->$method(...$args);
}
public function __call($method, $parameters)
{
if (static::hasMacro($method)) {
return $this->macroCall($method, $parameters);
}
// 将不存在的方法的调用委托给 RouteRegistrar 处理,
return (new RouteRegistrar($this))->attribute($method, $parameters[0]);
}
public function attribute($key, $value)
{
// 只允许指定的属性设置($allowedAttributes = ['as', 'domain', 'middleware', 'name', 'namespace', 'prefix',])
if (! in_array($key, $this->allowedAttributes)) {
throw new InvalidArgumentException("Attribute [{$key}] does not exist.");
}
// 支持.方式来存放属性
$this->attributes[array_get($this->aliases, $key, $key)] = $value;
return $this;
}
public function group($callback)
{
$this->router->group($this->attributes, $callback);
}
public function group(array $attributes, $routes)
{
$this->updateGroupStack($attributes);
$this->loadRoutes($routes);
array_pop($this->groupStack);
}
protected function loadRoutes($routes)
{
if ($routes instanceof Closure) {
$routes($this);
} else {
$router = $this;
require $routes;
}
}
小结
Route::middleware('web')
->namespace($this->namespace)
->group(base_path('routes/web.php'));
实际就是将 middleware namespace 加入到 RouteRegistrar 对象里面的 attributes 数组属性,并返回
RouteRegistrar 对象,再调用 RouteRegistrar 对象的 group 方法,也就是调用 router 对象的 group
方法。最终就是将['middleware' => 'web', 'namespace' => $this->namespace] 数组设置给
$this->router 的groupStack 属性(将运用到所有的路由),再加载 config/web.php。