0
点赞
收藏
分享

微信扫一扫

「造个轮子」——设计 HTTP 请求全局上下文


「造个轮子」——设计 HTTP 请求全局上下文_json

前言

本次 ​​Cicada​​​ 已经更新到了  ​v1.0.3​。

主要是解决了两个 issue,#9(Boss线程数好像设置有误 ) #8(怎么返回纯字符串内容不要JSON格式?)。

所以本次的主要更新为:

  • Cicada 采用合理的线程分配来处理接入请求线程以及 IO 线程。
  • 支持多种响应方式(以前只有 json,现在支持 text)。
  • 为了满足上者引入了 ​context​。
  • 优雅停机。

其中我觉得最核心也最有用的就是这个 ​Context​,并为此重构了大部分代码。

多种响应方式

在起初 ​Cicada​​ 默认只能响应 ​json​,这一点确实不够灵活。加上后续也打算支持模板解析,所以不如直接在 API 中加入可让用户自行选择不同的响应方式。

因此调整后的 API 如下。

想要输出 ​text/plain​ 时。

  1. @CicadaAction("textAction")
  2. public class TextAction implements WorkAction {
  3.    @Override
  4.    public void execute(CicadaContext context, Param param) throws Exception {
  5.        String url = context.request().getUrl();
  6.        String method = context.request().getMethod();
  7.        context.text("hello world url=" + url + " method=" + method);
  8.    }
  9. }

而响应输出 ​application/json​​ 时只需要把需要响应的对象写入到 ​json()​ 方法中.

「造个轮子」——设计 HTTP 请求全局上下文_源码分析_02

因此原有的业务 action 中也加入了一个上下文的参数:

  1. /**
  2. * abstract execute method
  3. * @param context current context
  4. * @param param request params
  5. * @throws Exception throw exception
  6. */
  7. void execute(CicadaContext context ,Param param) throws Exception;

下面就来看看这个 ​Context​ 是如何完成的。

Cicada Context

先看看有了这个上下文之后可以做什么。

比如有些场景下我们需要拿到本次请求中的头信息,这时就可以通过这个 ​Context​ 对象直接获取。

当然不止是头信息:

  • 获取请求头。
  • 设置响应头。
  • 设置 ​cookie​。
  • 获取请求 ​URL​。
  • 获取请求的 ​method​(get/post)等。

其实通过这些特点可以看出这些信息其实都和一次 ​请求、响应​ 密切相关,并且各个请求之间的信息应互不影响。

这样的特性是不是非常熟悉,没错那就是 ​ThreadLocal​,它可以将每个线程的信息存储起来互不影响。

ThreadLocal 的原理本次不做过多分析,只谈它在 Cicada 中的应用。

CicadaContext.class

先来看看 ​CicadaContext​ 这个类的主要成员变量以及方法。

「造个轮子」——设计 HTTP 请求全局上下文_源码分析_03

成员变量是两个接口 ​CicadaRequestCicadaResponse​,名称就能看出肯定是存放请求和响应数据的。

HttpDispatcher.class

想要存放本次请求的上下文自然是在真正请求分发的地方 ​HttpDispatcher​。

「造个轮子」——设计 HTTP 请求全局上下文_源码分析_04

这里改的较大的就是两个红框处,第一部分是做上下文初始化及赋值。

第二部分自然就是卸载上下文。

先看初始化。

CicadaRequestcicadaRequest=CicadaHttpRequest.init(defaultHttpRequest);

首先是将 request 初始化:

CicadaHttpRequest​​ 自然是实现了 ​CicadaRequest​ 接口:

「造个轮子」——设计 HTTP 请求全局上下文_源码分析_05

这里只保存了请求的 URL、method 等信息,后续要加的请求头也存放在此处即可。

Response​ 也是同理的。

「造个轮子」——设计 HTTP 请求全局上下文_源码分析_06

这两个具体的实现类都私有化了构造函数,防止外部破坏了整体性。

接着将当前请求的上下文保存到了 ​CicadaContext​ 中。

  1. CicadaContext.setContext(new CicadaContext(cicadaRequest,cicadaResponse));

而这个函数本质使用的则是 ​ThreadLocal​​ 来存放 ​CicadaContext​。

  1.    public static void setContext(CicadaContext context){
  2.        ThreadLocalHolder.setCicadaContext(context) ;
  3.    }

  4.    private static final ThreadLocal<CicadaContext> CICADA_CONTEXT= new ThreadLocal() ;

  5.    /**
  6.     * set cicada context
  7.     * @param context current context
  8.     */
  9.    public static void setCicadaContext(CicadaContext context){
  10.        CICADA_CONTEXT.set(context) ;
  11.    }

处理业务及响应

接着就是处理业务,调用不同的 API 做不同响应。

拿 ​context.text()​ 来说:

「造个轮子」——设计 HTTP 请求全局上下文_源码分析_07

其实就是设置了对应的响应方式、以及把响应内容写入了 ​CicadaResponse​​ 的 ​httpContent​ 中。

业务处理完后调用 ​responseContent()​ 进行响应:

  1. responseContent(ctx,CicadaContext.getResponse().getHttpContent());

其实就是在上下文中拿到的响应方式及响应内容返回给客户端。

卸载上下文

最后有点非常重要,那就是 卸载上下文

如果这里不做处理,之后随着请求的增多, ​ThreadLocal​ 里存放的数据也越来越多,最终肯定会导致内存溢出。

所以 ​CicadaContext.removeContext()​ 就是为了及时删除当前上下文。

优雅停机

最后还新增了一个停机的方法。

「造个轮子」——设计 HTTP 请求全局上下文_初始化_08

其实也就是利用 ​Hook​ 函数实现的。

由于目前 ​Cicada​ 开的线程,占用的资源都不是特别多,所以只是关闭了 Netty 所使用的线程。

如果后续新增了自身的线程等资源,那也可以全部放到这里来进行释放。

总结

Cicada​ 已经更新了 4 个版本,雏形都有了。

后续会重点实现模板解析和注解请求路由完成,把 ​MVC​​ 中的 ​view​ 完成就差不多了。

还没有了解的朋友可以点击下面链接进入主页了解下😋。

​​https://github.com/TogetherOS/cicada​​

「造个轮子」——设计 HTTP 请求全局上下文_源码分析_09





举报

相关推荐

0 条评论