使用 Servlet3.1 WriteListener进行异步响应输出以及踩过的坑

在标准的spring mvc项目中,当对象数据已经产生时,不管是输出json,还是view,最终均是将相应的数据直接写入response的outputStream中。这里的输出是同步式调用的,即意味着只有当整个数据完整地写到输出流中时,整个业务线程才会被认为执行结束。

这就意味着在传统的基于请求的慢速攻击之外,还有一种基于响应的慢速攻击,其思路即是客户端强制让整个接收变慢,而服务端因为缓存区不足以存储完整的响应数据,而被动地阻塞调用端,进而阻塞业务线程。

在Servlet 3.0版本中,提出了业务中的异步处理,即 通过 HttpServletRequest#startAsync 来开启异步处理。等业务处理完成之后,才通过 AsyncContext#complete 来结束处理。在中间,可以仍然通过 HttpServletResponse#getOutputStream 来输出数据. 这里的异步处理仅仅是将容器的处理线程解放出来,即当业务处理需要长时间或者需要故意挂起请求(如LongPull)时,才有相应的意义。在最终输出数据时,这里仍然是阻塞的,只不过是阻塞业务线程(而非容器线程).造成的后果即是缓慢地IO操作造成线程阻塞。

随着 NIO 的出现,所有Web容器均使用了Nio来处理请求,即当整个请求已经完整读取完毕之后,才转交由具体的业务线程来处理,即在这里的io读取均为非阻塞读取,由很少数的线程就可以处理上百(千)个请求的网络请求. 在 Servlet 3.1 版本中, 规范中给出了 异步响应的概念,即可以通过响应式来达到异步非阻塞输出数据的效果. 从调用端来看,调用write之后即刻返回,并不会阻塞业务线程。后续未刷新到缓冲区的数据将在后续通过标准Nio流程由web容器的IO线程负责处理.

一个参考使用例子如下所示(参考于 https://www.oracle.com/webfolder/technetwork/tutorials/obe/java/HTML5andServlet31/HTML5andServlet%203.1.html):

//开启异步
val context = request.startAsync();
val response = context.getResponse();
val servletOut = response.getOutputStream();

//定义响应监听器,以可写时输出相应的数据
val writeListener = new WriteListenerImpl(context, servletOut, actionQueue);
servletOut.setWriteListener(writeListener);

//一个参考的监听器实现
public class WriteListenerImpl implements WriteListener {
    private ServletOutputStream output = null;
    private Queue queue = null;
    private AsyncContext context = null;

    private boolean flag = false;

    @Override
    public void onWritePossible() throws IOException {
        if (flag) {
            return;
        }

        //这里仅当output.isReady() 时才会调用write方法,否则会报 IllegalStateException
        while (queue.peek() != null && output.isReady()) {
            val action = queue.poll();
            doWrite(action);
        }
    }

    private void doWrite(Action action) throws IOException {
        //已完成标记位
        if (action == Action.COMPLETE) {
            flag = true;
        }

        action.run(context, servletOut);
    }
}
继续阅读“使用 Servlet3.1 WriteListener进行异步响应输出以及踩过的坑”

alibaba fastjson(json序列化器)序列化部分源码解析-2-性能优化B

    上篇地址:http://www.iflym.com/index.php/code/alibaba-fastjson-serializer-source-analyse-2-performence-optimize-a.html
    前面讲了进行对象解析的两个方面,并讲了针对outWriter将不同类型的数据信息写到buf字符数组。本篇讲解对象解析的过程,即如何将不同类型的对象解析成outWriter所需要的序列信息。并考虑其中的性能优化。

    取得解析器    
    首先我们需要取得指定对象的json序列化器,以便使用特定的序列化器来序列化对象。因此,需要有一个方法来取得相对应的序列化器。在fastjson中,使用了一个类似map的结构来保存对象类型和及对应的解析器。对于对象类型,在整个fastjson中,分为以下几类:

    1    基本类型以及其包装类型,字符串
    2    基本类型数组以及包装类型数组
    3    Atomic类型
    4    JMX类型
    5    集合类型以及子类
    6    时间类型
    7    json类型
    8    对象数组类型
    9    javaBean类型

    对于第1,2,3,4类型,在fastjson中使用了一个全局的单态实例来保存相对应的解析器;第5类型,处理集合类型,对于集合类型及其,由于其处理逻辑均是一样,所以只需要针对子类作一些的处理,让其返回相对应的集合类型解析器即可;第6类型,时间处理器,将时间转化为类似yyyy-MM-ddTHH:mm:ss.SSS的格式;第7类型,处理fastjson专有jsonAwre类型;第8类型,处理对象的数组形式,即处理数组时,需要考虑数组中的统一对象类型;第9,即处理我们最常使用的对象,javaBean类型,这也是在项目中解析得最多的类型。

继续阅读“alibaba fastjson(json序列化器)序列化部分源码解析-2-性能优化B”

alibaba fastjson(json序列化器)序列化部分源码解析-1-总体分析

    fastjson官方地址: http://code.alibabatech.com/wiki/display/FastJSON/Home
    从javaeye上看到了阿里一位人士写的fastjson,特别是其中如何将java对象序列化成json字符串这段。笔者比较关注,因为在笔者的项目中就用了一个json序列化器(造的轮子)。就下载下来看了一看,先不说和笔者所用的轮子有何区别,单就用了一个简单的测试器,来测试一下两者的处理速度。测试代码就不贴了,简单地说下测试结果。在jvm充分优化的情况下(for循环执行了很多次之后),笔者所使用的java序列化器处理速度不是很均匀,在结尾有短暂的变化(可能与虚拟机回收有关系);而fastjson在后面的处理过程当中,一般很均匀(后来发现与使用的buf分配方式有关)。最主要的区别莫在于,fastjson的速度那是不能对比了。
    经过分析源码之后,发现fastjson在处理json优化上面还是下了很大的工夫的。笔者准备从以下几个方面对fastjson作一个简单的解析,也让使用fastjson的同学对fastjson有一个简单的认识。
        1    总体分析    分析json序列化的总体思路和解析过程
        2    性能分析A  针对字符生产部分(即outWriter)对不同类型数据的处理和与性能相关处理部分
        3    性别分析B  针对序列化过程部分(即objectSerializer)对不同类型的序列化过程处理和与性能相关处理部分
        4    对象解析分析    对javaBean解析部分和针对字段输出部分的处理和解析
    源码分析基于1.0.5版本。

    总体分析,首先上图,即fastjson的总体处理思想,其实也是所有json序列化器需要考虑的问题。
    在这里,需要考虑的主要有两个部分,一是临时保存在序列化过程中用于储存数据的容器,二是处理对象序列化的序列化器。
    在fastjson中,保存数据的容器使用了wirter,字符输出流,而且是自实现的一个字符输出流。相对原来的writer,追加了很多需要输出的信息的实现,比如输出一个字符串,输出一个字符,输出一个long类型数据等。而处理对象序列化的序列化器,而使用了责任链模式和工厂模式,将不同类型的java对象分散到不同的序列化器当中。而每个序列化器只处理与自身类型相对应的数据信息,这样就避免了在处理时,各种情况交织在一块,逻辑混乱的问题。
    下面就源码本身作一个分析,其中结合两个部分进行分析。

继续阅读“alibaba fastjson(json序列化器)序列化部分源码解析-1-总体分析”