我们知道,在 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. bzoj 4806: 炮【dp】

    同1801 注意到一行只能放012个炮,我们只需要知道列的状态,不用状压行 所以设f[i][j][k]表示前i行有j列有1个炮,有k列有2个炮的方案数 然后分情况讨论转移就行了 #include< ...

  2. 洛谷P4241 采摘毒瘤

    传送门 完了我连背包都不会了…… 考虑暴力,先枚举最小的数是哪个,设大小为$d_i$,个数为$k_i$,所有比它小的数的总和是$sum$,然后把所有比它小的全都装进背包,它以及比他大的做一个多重背包, ...

  3. 【原创】Maven安装和配置

    ι 版权声明:本文为博主原创文章,未经博主允许不得转载. 前提 利用maven进行java项目或J2EE项目开发,要求电脑已配置java开发环境(JDK) 下载 下载地址:http://maven.a ...

  4. 2017杭电多校第六场1008 Kirinriki

    传送门 Kirinriki Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) To ...

  5. ACM_排序

    除了sort,你还会什么 Time Limit: 1000/500ms (Java/Others) Problem Description: 给出若干人的年龄(1~100之间的整数),把它们按照从小到 ...

  6. focus、click、blur、display、float、border、absolute、relative、fixed

    onfocus:获取焦点,点击时,按着不放 onclick:点击松开之后,未点击其他处 onblur:点击松开之后,又点击其他处 display:block,none,inline block:单独占 ...

  7. NHibernate学习笔记(3)-实体反射到数据库

    一.开发环境 NHiberate版本:4.0.4 开发工具:VS2013 数据库:SQLServer2012 二.开发流程 1.编写领域类与映射文件 namespace Domain { public ...

  8. Echarts修改legend样式

    legend: { icon: 'rect', itemWidth: 20, itemHeight: 10, itemGap: 10}

  9. [ CodeForces 1063 B ] Labyrinth

    \(\\\) \(Description\) 给出一个四联通的\(N\times M\) 网格图和起点.图中有一些位置是障碍物. 现在上下移动步数不限,向左至多走 \(a\) 步,向右至多走 \(b\ ...

  10. php域名授权只需要一个函数

    <?php function allow_doamin(){ $is_allow=false; $url=trim($_SERVER['SERVER_NAME']); $arr_allow_do ...