laravel——路由解析

路由解析

路由服务提供者

路由是外界访问Laravel应用程序的通路。那服务提供者顾名思义就是提供服务的。一般我们都是在 Routes 文件下面的路由文件中定义路由访问方法,路由访问方法定义到我们的识别的过程,肯定 是需要路由组件进行相关的处理,那这个组件是怎么被装入到容量里面的呢? 这个就是由服务提供者来完成的。

路由的加载

router这个服务是在实例化应用程序Application时在构造方法里通过注册 RoutingServiceProvider 时绑定到服务容器 里的:

  public function __construct($basePath = null)
    {
        if ($basePath) {
            $this->setBasePath($basePath);
        }

        $this->registerBaseBindings();
        //注册服务提供者
        $this->registerBaseServiceProviders();
        $this->registerCoreContainerAliases();
    }
 protected function registerBaseServiceProviders()
    {
        $this->register(new EventServiceProvider($this));
        $this->register(new LogServiceProvider($this));
        //注册路由服务提供者
        $this->register(new RoutingServiceProvider($this));
    }

在这里插入图片描述
这个方法就是注册路由,我们点进去就可以看到

  /**
     * Register the router instance.
     *
     * @return void
     */
    protected function registerRouter()
    {
        $this->app->singleton('router', function ($app) {
            return new Router($app['events'], $app);
        });
    }

这是注册一个Router实例,调用的静态方法都对应于\Illuminate\Routing\Router类里的方法,这个类里 包含了与路由的注册、寻址、调度相关的方法。
既然路由的实例我们找到了,那么路由文件是怎么注册到容器中呢?
在\Illuminate\Routing\RoutingServiceProvider::register() 类中往容器对象的 $bindings 数组属性 以 key­value 形式注册进去,然后就会由服务提供者进行相关服务的注册,并通过引导服务( \Illuminate\Foundation\Bootstrap\BootProviders::class)下面的 Boot 方法来引导每个服务的执行操作
在这里插入图片描述
调用 \App\Providers\RouteServiceProvider::boot() 方法加载路由列表。在这当中会调用父类的boot方 法,获取到先去容器里面的Router的注册类 laravel 首先去寻找路由的缓存文件,没有缓存文件再去进行加载路由。

   public function boot()
    {
        $this->setRootControllerNamespace();

        if ($this->routesAreCached()) {
            $this->loadCachedRoutes();
        } else {
            $this->loadRoutes();-----》加载路由

            $this->app->booted(function () {
                $this->app['router']->getRoutes()->refreshNameLookups();
                $this->app['router']->getRoutes()->refreshActionLookups();
            });
        }
    }
    //加载 \App\Providers\RouteServiceProvider中的map方法
      protected function loadRoutes()
    {
        if (method_exists($this, 'map')) {
            $this->app->call([$this, 'map']);
        }
    }

调用 \App\Providers\RouteServiceProvider的map方法
在这里插入图片描述
通过map方法我们能看到 laravel将路由分为两个大组:api、web。这两个部分的路由分别写在两个文件中:routes/web.php、 routes/api.php。

路由的注册

通常都是用Route这个Facade调用静态方法get, post, head, options, put, patch, delete…等来注册路由。而Router这个实例我们第一步的时候就已经注册好了。

	public function get($uri, $action = null)
    {
        return $this->addRoute(['GET', 'HEAD'], $uri, $action);
    }
    public function post($uri, $action = null)
    {
        return $this->addRoute('POST', $uri, $action);
    }

其实这些方法都是调用addRoute这个方法

public function addRoute($methods, $uri, $action)
    {
        return $this->routes->add($this->createRoute($methods, $uri, $action));
    }

再里面首先要先“createRoute”之后再“add”

   protected function createRoute($methods, $uri, $action)
    {
        //判断当前路由是不是控制器的方法
        if ($this->actionReferencesController($action)) {
            //controller@action类型的路由在这类转换
            $action = $this->convertToControllerAction($action);
        }

        $route = $this->newRoute(
            $methods, $this->prefix($uri), $action
        );

        // 合并路由分组
        if ($this->hasGroupStack()) {
            $this->mergeGroupAttributesIntoRoute($route);
        }
        //添加路由条件
        $this->addWhereClausesToRoute($route);

        return $route;
    }

在createRoute方法里面转换了形式
在这里插入图片描述
经过转换之后,我们的路由变成这样的形式

[ 
'uses' => 'App\Http\Controllers\HomeController@index', 
'controller' => 'App\Http\Controllers\HomeController@index'
 ]

再看add方法

 public function add(Route $route)
    {
    	//添加到集合
        $this->addToCollections($route);
		//添加到查找表中
        $this->addLookups($route);

        return $route;
    }
     protected function addToCollections($route)
    {
        $domainAndUri = $route->getDomain().$route->uri();

        foreach ($route->methods() as $method) {
            $this->routes[$method][$domainAndUri] = $route;
        }

        $this->allRoutes[$method.$domainAndUri] = $route;
    }
    protected function addLookups($route)
    {
        if ($name = $route->getName()) {
            $this->nameList[$name] = $route;
        }
        $action = $route->getAction();

        if (isset($action['controller'])) {
            $this->addToActionList($action, $route);
        }
    }

经过这步操作,我们的路由变成了这种,放在下面4个属性表里面——routes、allRoutes、nameList、actionList
routes中存放了HTTP请求方法与路由对象的映射:

[ 
	'GET' => [ $routeUri1 => $routeObj1 
				... 
			]
		...
 ]

allRoutes属性里存放的内容时将routes属性里的二位数组变成一位数组后的内容:

[ 
	'GET' . $routeUri1 => $routeObj1 
	'GET' . $routeUri2 => $routeObj2
	 ... 
]

nameList是路由名称与路由对象的一个映射表

[ 
	$routeName1 => $routeObj1 
	... 
]

actionList是路由控制器方法字符串与路由对象的映射表

[ 
	'App\Http\Controllers\ControllerOne@ActionOne' => $routeObj1 
]

至此路由的注册就已经完成,下面就是最后一步,匹配相应的路由

路由的分发

路由查找是由HTTP请求在经过Pipeline通道上的中间件的前置操作后到达目的地:
在这里插入图片描述
在这里插入图片描述
这个方法就是请求经过一些中间件的验证,执行dispatchToRouter()方法。
在这里插入图片描述
最终路由的匹配就是在这个函数中完成的。点进去,发现先findRoute(),之后runRoute()

protected function findRoute($request)
    {
        $this->current = $route = $this->routes->match($request);

        $this->container->instance(Route::class, $route);

        return $route;
    }
protected function runRoute(Request $request, Route $route)
    {
        $request->setRouteResolver(function () use ($route) {
            return $route;
        });

        $this->events->dispatch(new Events\RouteMatched($route, $request));

        return $this->prepareResponse($request,
            $this->runRouteWithinStack($route, $request)
        );
    }

这里面要经过一些验证,验证成功之后需routes中存放了HTTP请求方法与路由对象的映射。

路由参数绑定

当路由通过了全部的认证就将会被返回,接下来就要将请求对象URI里的路径参数绑定赋值给路由参数

 public function bind(Request $request)
    {
        $this->compileRoute();

        $this->parameters = (new RouteParameterBinder($this))
                        ->parameters($request);

        $this->originalParameters = $this->parameters;

        return $this;
    }

经过绑定之后,紧接着就时候运行通过匹配路由中对应的控制器方法并返回响应对 象了
路由的寻址过程就结束了。
简化的整体流程图
整体思路

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值