vertx源码_vert.x-web的源码解析

本文主要分析vert.x-web的实现原理,尤其是Router、Route和RoutingContext的内部工作机制。首先介绍了Router作为Route容器的角色,以及如何通过Router进行路由匹配。接着探讨了Route的创建、设置和匹配路径的过程。同时,文章提到了subRouter的概念,用于组织和优化路由。通过对vert.x-web的源码解析,揭示了路由匹配和异常处理的细节,帮助读者深入理解vert.x-web的内部工作流程。
摘要由CSDN通过智能技术生成

本来应该要写的是eventbus的源码分析的,但是Vert.x中国用户组(群号:515203212)的小伙伴们好像对vert.x-web深入了解的需求更大一些。所以就先分析vert.x-web的实现原理吧。

分析完之后发现篇幅较长,请耐心看完。

如果哪里有写的不好的话,或者不好理解的地方,欢迎在评论区提出来,谢谢。

vert.x-web主要的功能是路由,还有常用的http相关工具(例如:BodyHandler,SessionHandler)。 本文主要围绕vert.x-web是如何实现路由来展开分析。

vert.x-web最主要的是3个类: Router, Route,RoutingContext。

本文分为以下几部分展开分析:Router的api接口和实现类RouterImpl

Route的api接口和实现类RouteImpl

RoutingContext的api接口和实现类RoutingContextImpl

路由过程

一. 先来看Router部分。

Router其实就是Route的容器, 里面装载了全部的Route。当request到来时,通过Router匹配容器里的多个Route。Router把路由的工作丢给RoutingContext做了。

Router相关的api基本都是创建Route(路由点)的。

例如,route(),get(), get(path), 还有创建正则请求路径的Route等等。

除了这些说些比较重要的。

public interface Router {

//省略若干代码... //路由的入口方法。request进来之后,匹配对应的Route void accept(HttpServerRequest request);

//在当前router中,挂载子router。 Router mountSubRouter(String mountPoint, Router subRouter);

//为当前router设置异常处理器 Router exceptionHandler(@Nullable Handler exceptionHandler);

//这两个方法是用在子router,不能直接调用。 void handleContext(RoutingContext context);

void handleFailure(RoutingContext context);

}

接着看看RouterImpl实现。

public class RouterImpl implements Router {

//省略若干代码... private final Vertx vertx;

//存储Route用的是skiplist,相比于List,时间复杂度从O(n)降低到O(lgn)。 //并且用的是线程安全的skiplist //routeComparator是排序比较器。 private final Set routes = new ConcurrentSkipListSet<>(routeComparator);

//用于route的序号,保证route在routes的顺序。 //排序前面的route的order比较小。 private final AtomicInteger orderSequence = new AtomicInteger();

//异常处理器,待会分析该异常处理器的调用处。 private Handler exceptionHandler;

public RouterImpl(Vertx vertx) {

this.vertx = vertx;

}

//随便放出点创建route的代码。此时并未将route加入routes容器中, //而是为route设置handler时才加到routes容器,稍后分析 public Route route(HttpMethod method, String path) {

return new RouteImpl(this, orderSequence.getAndIncrement(), method, path);

}

public Route route(String path) {

return new RouteImpl(this, orderSequence.getAndIncrement(), path);

}

public void accept(HttpServerRequest request) {

//... //请求委托为RoutingContext,由RoutingContext来实现路由。 //这里稍后解释,只需要记住accept方法是路由的入口方法。 new RoutingContextImpl(null, this, request, routes).next();

}

//分析挂载,所谓的挂载就是把一个有多个子Route的容器Router放到另一个Router(主router) //mountPoint,挂载点, public Router mountSubRouter(String mountPoint, Router subRouter) {

//挂载点的路径必须是确定的,不能用通配符和模式匹配 if (mountPoint.endsWith("*")) {

throw new IllegalArgumentException("Don't include * when mounting subrouter");

}

if (mountPoint.contains(":")) {

throw new IllegalArgumentException("Can't use patterns in subrouter mounts");

}

//这里就是创建route,然后request达到handler时,转交给subRouter的handleContext。 route(mountPoint + "*").handler(subRouter::handleContext)

.failureHandler(subRouter::handleFailure);

return this;

}

public void handleContext(RoutingContext ctx) {

//这里创建一个新的RoutingContext,并且把原来的routingContext包装进去, //还有子router(subRouter)的routes也传进去,然后调用next()在subRouter中路由。 new RoutingContextWrapper(getAndCheckRoutePath(ctx), ctx.request(), routes, ctx)

.next();

}

public void handleFailure(RoutingContext ctx) {

new RoutingContextWrapper(getAndCheckRoutePath(ctx), ctx.request(), routes, ctx)

.next();

}

//getAndCheckRoutePath获取挂载路径 private String getAndCheckRoutePath(RoutingContext ctx) {

//currentRoute的路径只有挂载路径,在mountSubRouter方法中可以看的出来。 Route currentRoute = ctx.currentRoute();

String path = currentRoute.getPath();

return path;

}

}

先大体看看RouterImpl实现过程,看完RoutingContext和Route再回头来看看Router。

再扯扯subRouter的作用。

如果把所有的route都放在一个Router中,当前功能点多的时候,可能就会有好几百个Route。那么请求路由到排在后面Route时,整个路由的开销可能会比较大点。

使用subRouter,可以把同个模块的功能放到一个subRouter下面。

例如: 用户添加,修改,删除,新增等等。

//示例代码Router mainRouter = Router.router(vertx);

Router userRouter = Router.router(vertx);

userRouter.get("/:userId")...

userRouter.post()...

userRouter.delete("/:userId")...

userRouter.put("/:userId")...

//挂载到主router上mainRouter .mountSubRouter("/user", userRouter);

//其他模块亦是如此, 最后就是mainRouter挂载了多个功能模块的subRouter//当前subRouter也还可以继续挂subRouter 一般没必要 二级基本能满足绝大多数情况了

二. 接下来分析Route和它的实现类RouteImpl

上面分析我们知道,Route的创建是在Router调用route或get或post等等时创建的。

route常用的方法一般就是设置一下handler。链式调用的方式

router.route().handler(handler);

相关方法也不少,主要就是设置各种http的参数。启动关闭Route(默认是启动的),还有让当前的Route在Router容器里排到最后的last()方法。

其中最重要的也是最复杂的,就是设置请求路径path。

public interface Route {

//省略若干代码... //一般不用此方法,直接在创建route的时候设置 Route path(String path);

//route的序号,一般就是用Router中的orderSequence累加生成的。 Route order(int order);

Route last();

//启用

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值