Синхронная альтернатива PipedInput / PipedOutput Stream API? - PullRequest
3 голосов
/ 18 мая 2019

У нас есть ServletFilter, который извлекает <title/> из ServletResponse. Мы делаем это, используя Piped*Stream API в нашем собственном расширении HttpServletResponseWrapper.

Чтобы быть более конкретным, текущий подход заключается в следующем (в псевдокоде):

  1. Создайте пару потоков PipedInput и PipedOutput и соедините их друг с другом.
  2. Введите PipedOutputStream в нашем расширении HttpServletResponseWrapper.
  3. Запустить поток, который ожидает записи байтов в PipedOutputStream (когда он будет готов, поток будет считывать <title/> с подключенного PipedInputStream).
  4. Передайте наше расширение от HttpServletResponseWrapper до filterChain.doFilter() (это позволяет Servlet обработать запрос и записать в PipedOutputStream.

И это фактический код:

        PipedInputStream pipedInputStream = new PipedInputStream( BUFFER_SIZE );
        PipedOutputStream pipedOutputStream = new PipedOutputStream( pipedInputStream );

        // ResponseSplitter extends HttpServletResponseWrapper.
        // When getOutputStream() is called, the splitter returns a class called
        // SplitStream, which extends ServletOutputStream, overriding the write() method by
        // writing to both the response's original outputStream and the pipedOutputStream.
        HttpServletResponseSplitter httpServletResponseSplitter =
                new HttpServletResponseSplitter(
                    httpServletResponse,
                    pipedOutputStream,
                    true );

        Future<?> future = null;
        try {
            // Fire off a thread that waits for the PipedInputStream to have 
            // content, then reads data.
            // Specifically, we pass the PipedInputStream to jericho
            // StreamedSource to examine the DOM segment-by-segment, without 
            // buffering the whole document into memory.
            future = recordHistory( httpServletResponseSplitter );

            // On the main thread, we pass the request and responseSplitter
            // down the chain so that the servlet can write to the
            // responseSplitter's splitStream
            chain.doFilter( httpServletRequest, httpServletResponseSplitter );

            // block until the servlet's done writing
            future.get();
        }
        catch ( Exception e ) {
            throw new RuntimeException( e );
        }

Мы пытаемся избежать сложности потоков, и в то же время можем читать документ response как поток и, таким образом, извлекать тег <title/> без буферизации весь документ в память.

Есть ли более простой синхронный подход к тому, что мы пытаемся сделать?

редактировать: добавлен фактический код

...