我们知道,在 Laravel 世界里,外界传进来一个 Request 时,会被 Kernel 处理并返回给外界一个 Response。Kernel 在处理 Request 时,会调用 illuminate/routing 包提供的路由功能,来根据当前的 Request,转发到对应的执行逻辑(执行逻辑的形式可以为 Closure 或 Controller@Action)。同时,在进入执行逻辑之前和之后,还会依次进入 Middlewares 的前置和后置处理。所以,一个 Request 由 Kernel 处理为一个 Response 的一个生命周期图如下:

根据上面的流程,理解路由系统的内部工作原理是非常重要的!当然,它也是非常复杂的。想要深入理解一个工具的使用,学习它的内部设计原理才是画龙点睛。在理解 illuminate/routing 如何工作之前,先设想如何去设计一个路由系统呢?一起想个三分钟吧。

  • 注册路由 :想想一个 Request 进入程序时,携带的请求信息类似为 GET https://localhost/api/v2/peop...,所以我们需要定义一个 Route 对象来表示这个信息,同时还得定义 RouteCollection(Route 的集合)来添加、获取和匹配出一个 Route。程序启动时,开发者定义的所有路由(Route)列表都会被注册到 RouteCollection 内。
  • 查找路由 :有了整个程序的路由列表,这样当一个 Request 进来时,再根据当前 Request 的信息匹配出一个合适的 Route,所以可以设计一个类似 RouterManager 对象,作用类似开发经理 Manager 的总体统筹,来调用 $router->findRoute(\$request): Route 匹配出合适的 Route。
  • 运行路由 :既然匹配出了对应 Route,那可以调用 RouterManager->runRoute($route): Response 得到对应的 Response 返回给外界。

所以,如果自己去设计一个路由系统,就可以按照上面三步去做,思路也很好理解。实际上,Laravel 的路由模块 illuminate/routing 也是按照这三个步骤来设计的。本文将会源码分析下 Laravel 是如何把开发者在 routes/*.php 中写的路由列表注册到 RouteCollection 对象内的。

我们知道,Laravel 在启动时第一步会去实例化 \Illuminate\Foundation\Application 对象,这个容器对象会去调用 \Illuminate\Routing\RoutingServiceProvider::register() 往容器对象的 $bindings 数组属性key-value 形式注册进来,注册的对象主要包括 Router(就是上文的 RouterManager 角色,把它比作为开发小组的开发经理角色)等。

然后会去调用 \App\Providers\RouteServiceProvider::boot() 方法默认加载 routes/api.php 和 routes/web.php 文件中注册的路由列表,并且以 Facade 模式去注册路由列表:


Route::prefix($prefix)->middleware($middleware)->group('xxx/web.php');

实际上就是调用 \Illuminate\Routing\RouteRegistrar 类里的 attribute(key, value) 方法以 key-value 形式注册到 attributes 数组属性里。最主要的 group(string) 方法调用的是 Router::group() 方法,然后调用 loadRoutes(routes) 去执行在 routes/api.php 和 routes/web.php 文件中定义的路由。对于每一种方法(如 GET、POST 等等方法)的路由,Router 对象内都有对应的方法来添加 Route 注册到 RouteCollection 中,比如常见的 get(uri, action) 方法,就是调用的 RouteCollection::add(route) 方法把 Route 注册到 RouteCollection 中。而 route 的创建,调用的是 Router::createRoute(methods, uri, action),其中由于 $action 可能是 Closure 或者 Controller@Action,如果是 Controller@Action 形式,则需要把字符串切割为数组形式,再传入 Route 类的构造函数里。

总结下注册路由所需要用到的对象:使用 Route 来表示路由信息,使用 RouteCollection 来表示路由集合列表,并且提供了添加删除方法来把 Route 注册到 RouteCollection 内,而 Router 才是纵览全局的角色,注册路由是通过该对象发起的,它会调用 RouteCollection 去注册路由,路由的元数据信息如路由名称等是用 RouteRegistrar 对象表示。从上文可知道,所有对象中,Router 才是画龙点睛的对象。

通过以上的分析,就能对 illuminate/routing 路由系统的基本设计越来越清晰。一个 Request 进来后,Application 首先开始启动并按照以上逻辑开始注册路由列表,然后就是根据当前 Request 信息查找对应的 Route 对象。

那如何根据当前 Request 信息查找出对应的 Route 的呢?见本系列第二篇文章。

原文地址:https://segmentfault.com/a/1190000015862083

illuminate/routing 源码分析之注册路由的更多相关文章

  1. Flask源码分析二:路由内部实现原理

    前言 Flask是目前为止我最喜欢的一个Python Web框架了,为了更好的掌握其内部实现机制,这两天准备学习下Flask的源码,将由浅入深跟大家分享下,其中Flask版本为1.1.1. 上次了解了 ...

  2. springMVC源码分析--AbstractHandlerMethodMapping注册url和HandlerMethod对应关系(十一)

    在上一篇博客springMVC源码分析--AbstractHandlerMethodMapping获取url和HandlerMethod对应关系(十)中我们简单地介绍了获取url和HandlerMet ...

  3. Spring Cloud Eureka源码分析 --- client 注册流程

    Eureka Client 是一个Java 客户端,用于简化与Eureka Server的交互,客户端同时也具备一个内置的.使用轮询负载算法的负载均衡器. 在应用启动后,将会向Eureka Serve ...

  4. Nacos(一)源码分析Nacos注册示例流程

    nacos官方地址:https://nacos.io/zh-cn/ 大家可以看一下nacos的中文手册以及官方源码,博主就不带领大家快速入门 了,官方文档中都有而且非常标准,比其他博客写的好多了并且还 ...

  5. ABP源码分析 - 约定注册(2)

    比较随意,记录下过程,以便忘了以后重拾. 所谓约定注册是指不需要明确写代码注入,只需要按约定规则写服务类,框架自动完成服务注册. 例如,只要这样写,框架就会自动注册. public class Tax ...

  6. Netty源码分析--Channel注册(上)(五)

    其实在将这一节之前,我们来分析一个东西,方便下面的工作好开展. 打开启动类,最开始的时候创建了一个NioEventLoopGroup 事件循环组,我们来跟一下这个. 这里bossGroup, 我传入了 ...

  7. Spring Cloud Eureka源码分析---服务注册

    本篇我们着重分析Eureka服务端的逻辑实现,主要涉及到服务的注册流程分析. 在Eureka的服务治理中,会涉及到下面一些概念: 服务注册:Eureka Client会通过发送REST请求的方式向Eu ...

  8. Netty源码分析--Channel注册(中)(六)

    接上一篇,我们继续看 不知道大家第一次看这段代码的时候有没有一脸懵逼,反正我是一脸懵,为什么这个if else 最终都是调用的register0方法,都是一样的. 其实这里就是为什么Netty是线程安 ...

  9. Netty源码分析--Channel注册&绑定端口(下)(七)

    接下来,我们看到的就是两个非常重要的方法 就是 processSelectedKeys() 和  runAllTasks() 方法了. selectionKey中ready的事件,如accept.co ...

随机推荐

  1. Win7 64 位 vs2012 pthread 配置

    1.      首先下载pthread,解压后我放在了e盘. 2.      然后用vs2012新建一个工程,然后右键项目属性,在配置属性->VC++目录->包含目录中输入E:\pthre ...

  2. bzoj 1854: [Scoi2010]游戏【匈牙利算法】

    没啥可说的,就是一边属性一边道具建二分图,把两个属性都连到道具上,然后枚举匹配,如果无法匹配就输出,时间戳优化 #include<iostream> #include<cstdio& ...

  3. P2570 [ZJOI2010]贪吃的老鼠

    传送门 →_→唯一一篇能看得懂的题解---->这里 很容易想到二分+网络流,然而并没有什么卵用--出题人的思路太神了-- 首先考虑如果一块奶酪在同一时间可以被多只老鼠吃的话,该如何建图.首先不难 ...

  4. P2476 [SCOI2008]着色方案

    传送门 数学太珂怕了--膜一下->这里 记\(sum[i]\)为题中\(c[i]\)的前缀和,\(C[i][j]\)表示\(C_{i}^j\) 设\(f[i][j]\)表示前面\(i\)中颜色已 ...

  5. 关于Anaconda环境变量配置遇到的一些情况说明

    安装和配置环境变量的话就不多说了,大家可以参照这个说的去做就行 https://blog.csdn.net/weixin_42997646/article/details/89414769 验证配置环 ...

  6. spring Cache /Redis 缓存 + Spring 的集成示例

    spring Cache https://www.ibm.com/developerworks/cn/opensource/os-cn-spring-cache/ spring+redis 缓存 ht ...

  7. eclipse mybatis 快速生成工具

    1.首先,得先看看eclipse有没安装mybatis generator插件,如果有的话,请忽略这一步 eclipse在线安装mybatis generator 1.打开eclipse,找到help ...

  8. 51nod1381 硬币游戏

    1381 硬币游戏 基准时间限制:1 秒 空间限制:131072 KB 分值: 5 难度:1级算法题  收藏  关注 有一个简单但是很有趣的游戏.在这个游戏中有一个硬币还有一张桌子,这张桌子上有很多平 ...

  9. 转】 Spark SQL UDF使用

    原博文出自于: http://blog.csdn.net/oopsoom/article/details/39401391 感谢! Spark1.1推出了Uer Define Function功能,用 ...

  10. hbase优化小结

    目录: 1,背景 2,GC 3,hbase cache 4,compaction 5,其他 1,背景 项目组中,hbase主要用来备份mysql数据库中的表.主要通过接入mysql binlog,经s ...