newtrekWang 2019-06-21
学 Laravel 和 Vuejs 你真应该来 codecasts.com !
Laravel route:cache
可以直接缓存路由文件,这样其实可以在一定程度上提高 Laravel 应用的性能,因为缓存路由之后,在访问应用的时候我们就不用再次去计算路由的消耗了,可以直接根据缓存文件来进行匹配处理。
然而,本文的讨论重点,还是 route:cache
背后的源码,是怎么做到这一步的。
route:cache
源码位于 Illuminate\Foundation\Console\RouteCacheCommand
你还是可以使用编辑器搜 RouteCacheCommand
,就可以看到源码了。
主要的代码逻辑就在 fire()
方法里面:
public function fire() { $this->call('route:clear'); //.... other codes }
执行 $this->call('route:clear')
,这部分的逻辑是:如果之前有缓存过路由文件,那么先清除旧的路由缓存,这个部分的代码位于 Illuminate\Foundation\Console\RouteClearCommand
中,还是看到 fire()
方法这里:
public function fire() { $this->files->delete($this->laravel->getCachedRoutesPath()); $this->info('Route cache cleared!'); }
主要就是执行删除动作,将之前的缓存路由删除;这个源码就在 Illuminate\Foundation\Application
的 getCachedRoutesPath()
中:
public function getCachedRoutesPath() { return $this->bootstrapPath().'/cache/routes.php'; }
所以这样一看,就是删除了 bootstrap/cache/routes.php
这个文件,那么这个文件其实就是 Laravel 的路由缓存文件,之后会重新生成这个 routes.php
文件。
获取所有的路由和其对应关系,在 RouteCacheCommand
的 fire()
方法往下:
public function fire() { //... codes $routes = $this->getFreshApplicationRoutes(); //... codes }
其中的 getFreshApplicationRoutes()
的代码是:
protected function getFreshApplicationRoutes() { return tap($this->getFreshApplication()['router']->getRoutes(), function ($routes) { $routes->refreshNameLookups(); $routes->refreshActionLookups(); }); }
这里又包含一个新的方法 getFreshApplication()
,这个方法也是位于同样的文件中:
protected function getFreshApplication() { return tap(require $this->laravel->bootstrapPath().'/app.php', function ($app) { $app->make(ConsoleKernelContract::class)->bootstrap(); }); }
这样一看,总结这两个方法做的事情就是:
getFreshApplication()
获取一个 Laravel 的核心实例, 然后上面的 getFreshApplicationRoutes()
中的 $this->getFreshApplication()['router']->getRoutes()
就可以理解了,也就是相当于 app('router')->getRoutes()
,这个 getRoutes()
就是负责获取所有路由,这部分的源码位于 Illuminate\Routing\Router
的 getRoutes()
中。
序列化所有路由注册映射关系,还是在 RouteCacheCommand
的 fire()
方法中:
public function fire() { foreach ($routes as $route) { $route->prepareForSerialization(); } }
上面的 prepareForSerialization()
方法位于 Illuminate\Routing\Route
中的 prepareForSerialization()
中。
序列化完成之后,将内容写入文件中,这个文件正是一开始删除的 bootstrap/cache/routes.php
,来看代码 RouteCacheCommand
的 fire()
方法:
$this->files->put( $this->laravel->getCachedRoutesPath(), $this->buildRouteCacheFile($routes) );
其中的 $this->laravel->getCachedRoutesPath()
在文章一开始就说明了,它是找到了 bootstrap/cache/routes.php
这个文件,然后写入的内容就是:
protected function buildRouteCacheFile(RouteCollection $routes) { $stub = $this->files->get(__DIR__.'/stubs/routes.stub'); return str_replace('{{routes}}', base64_encode(serialize($routes)), $stub); }
在这个方法中,看到 base64_encode(serialize($routes))
这行代码,所以你会在缓存的 routes.php
中看到类似下面的代码:
app('router')->setRoutes( unserialize(base64_decode('TzozNDoiSWxsdW1pbm...')) );
一堆 base64 的字符串,这些字符串 base64_decode()
出来大概是这样的:
这里就是完整的注册路由啦!
然后在下次访问 Laravel 项目的时候,就是可以直接从缓存的 routes 文件读取路由了。所以到这里,route:cache
的源码解读就完成了。
Happy Hacking