Tom_No_02 Servlet向流中打印内容,之后在调用finsihResponse,调用上是先发送了body,后发送Header的解释

上次在培训班学上网课的时候就发现了这个问题,一直没有解决,昨天又碰到了,2-3小时也未能发现点端倪,今早又仔细缕了下,让我看了他的秘密

1.Servlet向流中打印内容,之后在调用finsihResponse,调用上是先发送了body,后发送Header的问题描述

public class ServletProcessor {
    public void process(HttpRequest request,HttpResponse response){
...
        try {
            servlet = (Servlet) myClass.newInstance();
            HttpRequestFacade requestFacade = new HttpRequestFacade(request);
            HttpResponseFacade responseFacade = new HttpResponseFacade(response);
            servlet.service(requestFacade, responseFacade);//先调用servlet代码
            ((HttpResponse) response).finishResponse();//后执行完成response
        }
        catch (Exception e) {
            System.out.println(e.toString());
        }
        catch (Throwable e) {
            System.out.println(e.toString());
        }
    }
}
servlet.service(requestFacade, responseFacade);//先调用servlet代码
public class PrimitiveServlet implements Servlet {

  public void init(ServletConfig config) throws ServletException {
    System.out.println("init");
  }
  public void service(ServletRequest request, ServletResponse response)
    throws ServletException, IOException {
    System.out.println("from service");
    PrintWriter out = response.getWriter();//这里是关键稍后分析
    out.println("Hello. Roses are red.");//打印
    out.print("Violets are blue.");
  }
  public void destroy() {
    System.out.println("destroy");
  }
  public String getServletInfo() {
    return null;
  }
  public ServletConfig getServletConfig() {
    return null;
  }

}
((HttpResponse) response).finishResponse();//后执行完成response

    public void finishResponse()throws IOException{
         sendHeaders();
        // Flush and close the appropriate output mechanism
        if(writer !=null){
            writer.flush();
            System.out.println("finishResponse writer.flush");
            writer.close();
        }
    }

protected void sendHeaders() throws IOException{
        if(isCommitted())
            return;
        OutputStreamWriter osr=null;
        try{
            osr=new OutputStreamWriter(getStream(),getCharacterEncoding());
        }catch (UnsupportedEncodingException e) {
            osr = new OutputStreamWriter(getStream());
        }
        final PrintWriter outputWriter = new PrintWriter(osr);
        outputWriter.print(this.getProtocol());
        outputWriter.print(" ");
        outputWriter.print(status);
        if(message!=null){
            outputWriter.print(" ");
            outputWriter.print(message); //OK 状态描述
        }
        outputWriter.print("\r\n");
        if (getContentType()!=null){
            outputWriter.print("Content-Type: " + getContentType() + "\r\n");
        }
        if(getContentLength()>=0){
            outputWriter.print("Content-Length: " + getContentLength() + "\r\n");
        }
        synchronized (headers){
                Iterator items=headers.keySet().iterator();
                while(items.hasNext()){
                    String name=(String)items.next();
                    ArrayList list =(ArrayList) headers.get(name);
                    Iterator iterator = list.iterator();
                    while (iterator.hasNext()){
                        String value = (String)iterator.next();
                        outputWriter.print(name);
                        outputWriter.print(": ");
                        outputWriter.print(value);
                        outputWriter.print("\r\n");
                    }
                }
        }
        synchronized (cookies){
            Iterator items=cookies.iterator();
            while(items.hasNext()){
                Cookie cookie=(Cookie)items.next();
                outputWriter.print(CookieTools.getCookieHeaderName(cookie));
                outputWriter.print(": ");
                outputWriter.print(CookieTools.getCookieHeaderValue(cookie));
                outputWriter.print("\r\n");
            }
        }
        // Send a terminating blank line to mark the end of the headers
        outputWriter.print("\r\n");
        outputWriter.flush();
        System.out.println("给response的header发送完成");

        committed = true;
    }

 问题描述完毕

2.突破口,在sendHeader中的outputWriter与servlet中的 PrintWriter out = response.getWriter();不是一个东西

先说sentHader中的

 try{
            osr=new OutputStreamWriter(getStream(),getCharacterEncoding());
        }catch (UnsupportedEncodingException e) {
            osr = new OutputStreamWriter(getStream());
        }
        final PrintWriter outputWriter = new PrintWriter(osr);
        outputWriter.print(this.getProtocol());
        outputWriter.print(" ");
        outputWriter.print(status);
其中
    public OutputStream getStream(){
        return this.output;
    }
构造方法
    public HttpResponse(OutputStream output)
    {
        this.output=output;
    }
他被调用位置见图片

小结:sendheader中的PrintWriter就是使用了outputSteam做为底层的输出流

3.servlet中的 PrintWriter out = response.getWriter()的包裹关系

    public PrintWriter getWriter() throws IOException{
        ResponseStream newStream = new ResponseStream(this);
        newStream.setCommit(false);
        OutputStreamWriter osr=
                new OutputStreamWriter(newStream,getCharacterEncoding());
        writer=new ResponseWriter(osr);
        return  writer;
    }

见解释图

 

说明:

1.servlet中getWrter得到是ResponseWriter,调用responseWriter的frint("")方法,通过流的调用,最后底层流是ResponseStream,调用其方法为writer(...)

  writer方法是将"Rode Are Red" 字符串写入到HttpResponse的成员变量buff中

2.在调用close的时候,最后调用ResponseStream的close方法,接着在flushbuffer中才最终叫内容"Rode Are Red",发送给浏览器

几张debugger图

atzhang

posted @ 2020-09-03 10:32  张艳涛&java  阅读(235)  评论(0编辑  收藏  举报