coyote中的Request&Response&ReuestInfo

Request类是一个final类,该类是一个高效的server请求。

该类实例化之后许多参数不会被GC回收。同时该类所拥有的信息不会在初始化的时候就转换成可被用户直接使用的字符串的形式,大部分是以MessageBytes的形式存放,在被用户使用的时候才会进行转换,这样就大大提高了服务器的处理效率。
	// ----------------------------------------------------------- Constructors
	/**
	 * 构造方法 
	 */
	public Request() {
		parameters.setQuery(queryMB);
		parameters.setURLDecoder(urlDecoder);
	}

	// ----------------------------------------------------- Instance Variables
	/**
	 * 变量
	 */
	private int serverPort = -1;
	// 服务器名称
	private MessageBytes serverNameMB = MessageBytes.newInstance();
	
	// 远程的端口
	private int remotePort;
	// 本地的端口
	private int localPort;
	// 请求策略
	private MessageBytes schemeMB = MessageBytes.newInstance();
	// 请求方法
	private MessageBytes methodMB = MessageBytes.newInstance();
	// 未处理的URI
	private MessageBytes unparsedURIMB = MessageBytes.newInstance();
	// URI
	private MessageBytes uriMB = MessageBytes.newInstance();
	// 转码之后的URI
	private MessageBytes decodedUriMB = MessageBytes.newInstance();
	// 请求
	private MessageBytes queryMB = MessageBytes.newInstance();
	// 原型
	private MessageBytes protoMB = MessageBytes.newInstance();

	// 远程地址
	private MessageBytes remoteAddrMB = MessageBytes.newInstance();
	private MessageBytes localNameMB = MessageBytes.newInstance();
	private MessageBytes remoteHostMB = MessageBytes.newInstance();
	private MessageBytes localAddrMB = MessageBytes.newInstance();

	// http头部
	private MimeHeaders headers = new MimeHeaders();

	private MessageBytes instanceId = MessageBytes.newInstance();

	/**
	 * Notes.
	 */
	private Object notes[] = new Object[Constants.MAX_NOTES];

	/**
	 * 关联的输入缓存
	 */
	private InputBuffer inputBuffer = null;

	/**
	 * URL转码器.
	 */
	private UDecoder urlDecoder = new UDecoder();

	/**
	 * HTTP的常量
	 */
	private long contentLength = -1;
	private MessageBytes contentTypeMB = null;
	private String charEncoding = null;
	private Cookies cookies = new Cookies(headers);
	private Parameters parameters = new Parameters();

	private MessageBytes remoteUser = MessageBytes.newInstance();
	private MessageBytes authType = MessageBytes.newInstance();
	private HashMap<String, Object> attributes = new HashMap<String, Object>();

	private Response response;
	private ActionHook hook;

	private int bytesRead = 0;
	// Time of the request - useful to avoid repeated calls to
	// System.currentTime
	private long startTime = -1;
	private int available = 0;

	private RequestInfo reqProcessorMX = new RequestInfo(this);

	// ------------------------------------------------------------- Properties

	/**
	 * Get the instance id (or JVM route). Currently Ajp is sending it with each
	 * request. In future this should be fixed, and sent only once ( or
	 * 'negotiated' at config time so both tomcat and apache share the same
	 * name.
	 * 
	 * @return the instance id
	 */
	public MessageBytes instanceId() {
		return instanceId;
	}

	public MimeHeaders getMimeHeaders() {
		return headers;
	}

	public UDecoder getURLDecoder() {
		return urlDecoder;
	}

	// -------------------- Request data --------------------
	/**
	 * 请求数据
	 * 
	 * @return
	 */
	public MessageBytes scheme() {
		return schemeMB;
	}

	public MessageBytes method() {
		return methodMB;
	}

	public MessageBytes unparsedURI() {
		return unparsedURIMB;
	}

	public MessageBytes requestURI() {
		return uriMB;
	}

	public MessageBytes decodedURI() {
		return decodedUriMB;
	}

	public MessageBytes queryString() {
		return queryMB;
	}

	public MessageBytes protocol() {
		return protoMB;
	}

	/**
	 * Return the buffer holding the server name, if any. Use isNull() to check
	 * if there is no value set. This is the "virtual host", derived from the
	 * Host: header.
	 */
	public MessageBytes serverName() {
		return serverNameMB;
	}

	public int getServerPort() {
		return serverPort;
	}

	public void setServerPort(int serverPort) {
		this.serverPort = serverPort;
	}

	public MessageBytes remoteAddr() {
		return remoteAddrMB;
	}

	public MessageBytes remoteHost() {
		return remoteHostMB;
	}

	public MessageBytes localName() {
		return localNameMB;
	}

	public MessageBytes localAddr() {
		return localAddrMB;
	}

	public int getRemotePort() {
		return remotePort;
	}

	public void setRemotePort(int port) {
		this.remotePort = port;
	}

	public int getLocalPort() {
		return localPort;
	}

	public void setLocalPort(int port) {
		this.localPort = port;
	}

	// -------------------- encoding/type --------------------

	/**
	 * Get the character encoding used for this request.
	 */
	public String getCharacterEncoding() {

		if (charEncoding != null)
			return charEncoding;

		charEncoding = ContentType.getCharsetFromContentType(getContentType());
		return charEncoding;

	}

	public void setCharacterEncoding(String enc) {
		this.charEncoding = enc;
	}

	public void setContentLength(long len) {
		this.contentLength = len;
	}

	public int getContentLength() {
		long length = getContentLengthLong();

		if (length < Integer.MAX_VALUE) {
			return (int) length;
		}
		return -1;
	}

	public long getContentLengthLong() {
		if (contentLength > -1)
			return contentLength;

		MessageBytes clB = headers.getUniqueValue("content-length");
		contentLength = (clB == null || clB.isNull()) ? -1 : clB.getLong();

		return contentLength;
	}

	public String getContentType() {
		contentType();
		if ((contentTypeMB == null) || contentTypeMB.isNull())
			return null;
		return contentTypeMB.toString();
	}

	public void setContentType(String type) {
		contentTypeMB.setString(type);
	}

	public MessageBytes contentType() {
		if (contentTypeMB == null)
			contentTypeMB = headers.getValue("content-type");
		return contentTypeMB;
	}

	public void setContentType(MessageBytes mb) {
		contentTypeMB = mb;
	}

	public String getHeader(String name) {
		return headers.getHeader(name);
	}

	// -------------------- Associated response --------------------

	public Response getResponse() {
		return response;
	}

	public void setResponse(Response response) {
		this.response = response;
		response.setRequest(this);
	}

	public void action(ActionCode actionCode, Object param) {
		if (hook == null && response != null)
			hook = response.getHook();

		if (hook != null) {
			if (param == null)
				hook.action(actionCode, this);
			else
				hook.action(actionCode, param);
		}
	}

	// -------------------- Cookies --------------------

	public Cookies getCookies() {
		return cookies;
	}

	// -------------------- Parameters --------------------

	public Parameters getParameters() {
		return parameters;
	}

	// -------------------- Other attributes --------------------
	// We can use notes for most - need to discuss what is of general interest

	public void setAttribute(String name, Object o) {
		attributes.put(name, o);
	}

	public HashMap<String, Object> getAttributes() {
		return attributes;
	}

	public Object getAttribute(String name) {
		return attributes.get(name);
	}

	public MessageBytes getRemoteUser() {
		return remoteUser;
	}

	public MessageBytes getAuthType() {
		return authType;
	}

	public int getAvailable() {
		return available;
	}

	public void setAvailable(int available) {
		this.available = available;
	}

	// -------------------- Input Buffer --------------------

	public InputBuffer getInputBuffer() {
		return inputBuffer;
	}

	public void setInputBuffer(InputBuffer inputBuffer) {
		this.inputBuffer = inputBuffer;
	}

	/**
	 * Read data from the input buffer and put it into a byte chunk.
	 * 
	 * The buffer is owned by the protocol implementation - it will be reused on
	 * the next read. The Adapter must either process the data in place or copy
	 * it to a separate buffer if it needs to hold it. In most cases this is
	 * done during byte->char conversions or via InputStream. Unlike
	 * InputStream, this interface allows the app to process data in place,
	 * without copy.
	 * 
	 */
	public int doRead(ByteChunk chunk) throws IOException {
		int n = inputBuffer.doRead(chunk, this);
		if (n > 0) {
			bytesRead += n;
		}
		return n;
	}

	// -------------------- debug --------------------

	@Override
	public String toString() {
		return "R( " + requestURI().toString() + ")";
	}

	public long getStartTime() {
		return startTime;
	}

	public void setStartTime(long startTime) {
		this.startTime = startTime;
	}

	// -------------------- Per-Request "notes" --------------------

	/**
	 * Used to store private data. Thread data could be used instead - but if
	 * you have the req, getting/setting a note is just a array access, may be
	 * faster than ThreadLocal for very frequent operations.
	 * 
	 * Example use: Jk: HandlerRequest.HOSTBUFFER = 10 CharChunk, buffer for
	 * Host decoding WorkerEnv: SSL_CERT_NOTE=16 - MessageBytes containing the
	 * cert
	 * 
	 * Catalina CoyoteAdapter: ADAPTER_NOTES = 1 - stores the HttpServletRequest
	 * object ( req/res)
	 * 
	 * To avoid conflicts, note in the range 0 - 8 are reserved for the servlet
	 * container ( catalina connector, etc ), and values in 9 - 16 for connector
	 * use.
	 * 
	 * 17-31 range is not allocated or used.
	 */
	public final void setNote(int pos, Object value) {
		notes[pos] = value;
	}

	public final Object getNote(int pos) {
		return notes[pos];
	}

	// -------------------- Recycling --------------------

	public void recycle() {
		bytesRead = 0;

		contentLength = -1;
		contentTypeMB = null;
		charEncoding = null;
		headers.recycle();
		serverNameMB.recycle();
		serverPort = -1;
		localNameMB.recycle();
		localPort = -1;
		remotePort = -1;
		available = 0;

		cookies.recycle();
		parameters.recycle();

		unparsedURIMB.recycle();
		uriMB.recycle();
		decodedUriMB.recycle();
		queryMB.recycle();
		methodMB.recycle();
		protoMB.recycle();

		schemeMB.recycle();

		instanceId.recycle();
		remoteUser.recycle();
		authType.recycle();
		attributes.clear();

		startTime = -1;
	}

	// -------------------- Info --------------------
	public void updateCounters() {
		reqProcessorMX.updateCounters();
	}

	public RequestInfo getRequestProcessor() {
		return reqProcessorMX;
	}

	public int getBytesRead() {
		return bytesRead;
	}

	public boolean isProcessing() {
		return reqProcessorMX.getStage() == org.apache.coyote.Constants.STAGE_SERVICE;
	}

Response类也是一个final类。

// ----------------------------------------------------- Class Variables

    /**
     * Default locale as mandated by the spec.
     */
    private static Locale DEFAULT_LOCALE = Locale.getDefault();


    // ----------------------------------------------------- Instance Variables

    /**
     * Status code.
     */
    protected int status = 200;


    /**
     * Status message.
     */
    protected String message = null;


    /**
     * Response headers.
     */
    protected MimeHeaders headers = new MimeHeaders();


    /**
     * Associated output buffer.
     */
    protected OutputBuffer outputBuffer;


    /**
     * Notes.
     */
    protected Object notes[] = new Object[Constants.MAX_NOTES];


    /**
     * Committed flag.
     */
    protected boolean commited = false;


    /**
     * Action hook.
     */
    public ActionHook hook;


    /**
     * HTTP specific fields.
     */
    protected String contentType = null;
    protected String contentLanguage = null;
    protected String characterEncoding = Constants.DEFAULT_CHARACTER_ENCODING;
    protected long contentLength = -1;
    private Locale locale = DEFAULT_LOCALE;

    // General informations
    private long contentWritten = 0;
    private long commitTime = -1;

    /**
     * Holds request error exception.
     */
    protected Exception errorException = null;

    /**
     * Has the charset been explicitly set.
     */
    protected boolean charsetSet = false;

    protected Request req;

    // ------------------------------------------------------------- Properties

    public Request getRequest() {
        return req;
    }

    public void setRequest( Request req ) {
        this.req=req;
    }

    public OutputBuffer getOutputBuffer() {
        return outputBuffer;
    }


    public void setOutputBuffer(OutputBuffer outputBuffer) {
        this.outputBuffer = outputBuffer;
    }


    public MimeHeaders getMimeHeaders() {
        return headers;
    }


    public ActionHook getHook() {
        return hook;
    }


    public void setHook(ActionHook hook) {
        this.hook = hook;
    }


    // -------------------- Per-Response "notes" --------------------


    public final void setNote(int pos, Object value) {
        notes[pos] = value;
    }


    public final Object getNote(int pos) {
        return notes[pos];
    }


    // -------------------- Actions --------------------


    public void action(ActionCode actionCode, Object param) {
        if (hook != null) {
            if( param==null ) 
                hook.action(actionCode, this);
            else
                hook.action(actionCode, param);
        }
    }


    // -------------------- State --------------------


    public int getStatus() {
        return status;
    }

    
    /** 
     * Set the response status 
     */ 
    public void setStatus( int status ) {
        this.status = status;
    }


    /**
     * Get the status message.
     */
    public String getMessage() {
        return message;
    }


    /**
     * Set the status message.
     */
    public void setMessage(String message) {
        this.message = message;
    }


    public boolean isCommitted() {
        return commited;
    }


    public void setCommitted(boolean v) {
        if (v && !this.commited) {
            this.commitTime = System.currentTimeMillis();
        }
        this.commited = v;
    }

    /**
     * Return the time the response was committed (based on System.currentTimeMillis).
     *
     * @return the time the response was committed
     */
    public long getCommitTime() {
        return commitTime;
    }

    // -----------------Error State --------------------


    /** 
     * Set the error Exception that occurred during
     * request processing.
     */
    public void setErrorException(Exception ex) {
        errorException = ex;
    }


    /** 
     * Get the Exception that occurred during request
     * processing.
     */
    public Exception getErrorException() {
        return errorException;
    }


    public boolean isExceptionPresent() {
        return ( errorException != null );
    }


    // -------------------- Methods --------------------

    public void reset() throws IllegalStateException {
        
        if (commited) {
            throw new IllegalStateException();
        }

        recycle();

        // Reset the stream
        action(ActionCode.RESET, this);
    }


    public void finish() {
        action(ActionCode.CLOSE, this);
    }


    public void acknowledge() {
        action(ActionCode.ACK, this);
    }


    // -------------------- Headers --------------------
    /**
     * Warning: This method always returns <code>false<code> for Content-Type
     * and Content-Length.
     */
    public boolean containsHeader(String name) {
        return headers.getHeader(name) != null;
    }


    public void setHeader(String name, String value) {
        char cc=name.charAt(0);
        if( cc=='C' || cc=='c' ) {
            if( checkSpecialHeader(name, value) )
            return;
        }
        headers.setValue(name).setString( value);
    }


    public void addHeader(String name, String value) {
        char cc=name.charAt(0);
        if( cc=='C' || cc=='c' ) {
            if( checkSpecialHeader(name, value) )
            return;
        }
        headers.addValue(name).setString( value );
    }

    
    /** 
     * Set internal fields for special header names. 
     * Called from set/addHeader.
     * Return true if the header is special, no need to set the header.
     */
    private boolean checkSpecialHeader( String name, String value) {
        // XXX Eliminate redundant fields !!!
        // ( both header and in special fields )
        if( name.equalsIgnoreCase( "Content-Type" ) ) {
            setContentType( value );
            return true;
        }
        if( name.equalsIgnoreCase( "Content-Length" ) ) {
            try {
                long cL=Long.parseLong( value );
                setContentLength( cL );
                return true;
            } catch( NumberFormatException ex ) {
                // Do nothing - the spec doesn't have any "throws" 
                // and the user might know what he's doing
                return false;
            }
        }
        if( name.equalsIgnoreCase( "Content-Language" ) ) {
            // XXX XXX Need to construct Locale or something else
        }
        return false;
    }


    /** Signal that we're done with the headers, and body will follow.
     *  Any implementation needs to notify ContextManager, to allow
     *  interceptors to fix headers.
     */
    public void sendHeaders() {
        action(ActionCode.COMMIT, this);
        setCommitted(true);
    }


    // -------------------- I18N --------------------


    public Locale getLocale() {
        return locale;
    }

    /**
     * Called explicitly by user to set the Content-Language and
     * the default encoding
     */
    public void setLocale(Locale locale) {

        if (locale == null) {
            return;  // throw an exception?
        }

        // Save the locale for use by getLocale()
        this.locale = locale;

        // Set the contentLanguage for header output
        contentLanguage = locale.getLanguage();
        if ((contentLanguage != null) && (contentLanguage.length() > 0)) {
            String country = locale.getCountry();
            StringBuilder value = new StringBuilder(contentLanguage);
            if ((country != null) && (country.length() > 0)) {
                value.append('-');
                value.append(country);
            }
            contentLanguage = value.toString();
        }

    }

    /**
     * Return the content language.
     */
    public String getContentLanguage() {
        return contentLanguage;
    }

    /*
     * Overrides the name of the character encoding used in the body
     * of the response. This method must be called prior to writing output
     * using getWriter().
     *
     * @param charset String containing the name of the character encoding.
     */
    public void setCharacterEncoding(String charset) {

        if (isCommitted())
            return;
        if (charset == null)
            return;

        characterEncoding = charset;
        charsetSet=true;
    }

    public String getCharacterEncoding() {
        return characterEncoding;
    }

    /**
     * 设置响应类型.
     *
     * This method must preserve any response charset that may already have 
     * been set via a call to response.setContentType(), response.setLocale(),
     * or response.setCharacterEncoding().
     *
     * @param type the content type
     */
    public void setContentType(String type) {

        if (type == null) {
            this.contentType = null;
            return;
        }

        MediaType m = null;
        try {
             m = HttpParser.parseMediaType(new StringReader(type));
        } catch (IOException e) {
            // Ignore - null test below handles this
        }
        if (m == null) {
            // Invalid - Assume no charset and just pass through whatever
            // the user provided.
            this.contentType = type;
            return;
        }

        this.contentType = m.toStringNoCharset();

        String charsetValue = m.getCharset();

        if (charsetValue != null) {
            charsetValue = charsetValue.trim();
            if (charsetValue.length() > 0) {
                charsetSet = true;
                this.characterEncoding = charsetValue;
            }
        }
    }

    public void setContentTypeNoCharset(String type) {
        this.contentType = type;
    }

    public String getContentType() {

        String ret = contentType;

        if (ret != null 
            && characterEncoding != null
            && charsetSet) {
            ret = ret + ";charset=" + characterEncoding;
        }

        return ret;
    }
    
    public void setContentLength(long contentLength) {
        this.contentLength = contentLength;
    }

    public int getContentLength() {
        long length = getContentLengthLong();
        
        if (length < Integer.MAX_VALUE) {
            return (int) length;
        }
        return -1;
    }
    
    public long getContentLengthLong() {
        return contentLength;
    }


    /** 
     * Write a chunk of bytes.
     */
    public void doWrite(ByteChunk chunk/*byte buffer[], int pos, int count*/)
        throws IOException
    {
        outputBuffer.doWrite(chunk, this);
        contentWritten+=chunk.getLength();
    }

    // --------------------
    
    public void recycle() {
        
        contentType = null;
        contentLanguage = null;
        locale = DEFAULT_LOCALE;
        characterEncoding = Constants.DEFAULT_CHARACTER_ENCODING;
        charsetSet = false;
        contentLength = -1;
        status = 200;
        message = null;
        commited = false;
        commitTime = -1;
        errorException = null;
        headers.clear();

        // update counters
        contentWritten=0;
    }

    /**
     * Bytes written by application - i.e. before compression, chunking, etc.
     */
    public long getContentWritten() {
        return contentWritten;
    }
    
    /**
     * Bytes written to socket - i.e. after compression, chunking, etc.
     */
    public long getBytesWritten(boolean flush) {
        if (flush) {
            action(ActionCode.CLIENT_FLUSH, this);
        }
        return outputBuffer.getBytesWritten();
    }

RequestInfo类保存了Requet和Response对象的结构

RequestGroupInfo global = null;

	// ----------------------------------------------------------- Constructors
	/**
	 * 构造方法
	 * @param req
	 */
	public RequestInfo(Request req) {
		this.req = req;
	}

	public RequestGroupInfo getGlobalProcessor() {
		return global;
	}

	public void setGlobalProcessor(RequestGroupInfo global) {
		if (global != null) {
			this.global = global;
			global.addRequestProcessor(this);
		} else {
			if (this.global != null) {
				this.global.removeRequestProcessor(this);
				this.global = null;
			}
		}
	}

	// ----------------------------------------------------- Instance Variables
	/**
	 * 变量
	 */
	Request req;
	int stage = Constants.STAGE_NEW;
	String workerThreadName;
	ObjectName rpName;

	// -------------------- Information about the current request -----------
	// This is useful for long-running requests only

	public String getMethod() {
		return req.method().toString();
	}

	public String getCurrentUri() {
		return req.requestURI().toString();
	}

	public String getCurrentQueryString() {
		return req.queryString().toString();
	}

	public String getProtocol() {
		return req.protocol().toString();
	}

	public String getVirtualHost() {
		return req.serverName().toString();
	}

	public int getServerPort() {
		return req.getServerPort();
	}

	public String getRemoteAddr() {
		req.action(ActionCode.REQ_HOST_ADDR_ATTRIBUTE, null);
		return req.remoteAddr().toString();
	}

	/**
	 * Obtain the remote address for this connection as reported by an
	 * intermediate proxy (if any).
	 */
	public String getRemoteAddrForwarded() {
		String remoteAddrProxy = (String) req
				.getAttribute(Constants.REMOTE_ADDR_ATTRIBUTE);
		if (remoteAddrProxy == null) {
			return getRemoteAddr();
		}
		return remoteAddrProxy;
	}

	public int getContentLength() {
		return req.getContentLength();
	}

	public long getRequestBytesReceived() {
		return req.getBytesRead();
	}

	public long getRequestBytesSent() {
		return req.getResponse().getContentWritten();
	}

	public long getRequestProcessingTime() {
		if (getStage() == org.apache.coyote.Constants.STAGE_ENDED)
			return 0;
		else
			return (System.currentTimeMillis() - req.getStartTime());
	}

	// -------------------- Statistical data --------------------
	// Collected at the end of each request.
	// 在每个请求的最后收集
	private long bytesSent;
	private long bytesReceived;

	// Total time = divide by requestCount to get average.
	private long processingTime;
	// The longest response time for a request
	private long maxTime;
	// URI of the request that took maxTime
	private String maxRequestUri;

	private int requestCount;
	// number of response codes >= 400
	private int errorCount;

	// the time of the last request
	private long lastRequestProcessingTime = 0;

	/**
	 * 在请求被回收之前由Processor调用。它将收集一些静态信息
	 * Called by the processor before recycling the request. It'll collect
	 * statistic information.
	 */
	void updateCounters() {
		bytesReceived += req.getBytesRead();
		bytesSent += req.getResponse().getContentWritten();

		requestCount++;
		if (req.getResponse().getStatus() >= 400)
			errorCount++;
		long t0 = req.getStartTime();
		long t1 = System.currentTimeMillis();
		long time = t1 - t0;
		this.lastRequestProcessingTime = time;
		processingTime += time;
		if (maxTime < time) {
			maxTime = time;
			maxRequestUri = req.requestURI().toString();
		}
	}

	public int getStage() {
		return stage;
	}

	public void setStage(int stage) {
		this.stage = stage;
	}

	public long getBytesSent() {
		return bytesSent;
	}

	public void setBytesSent(long bytesSent) {
		this.bytesSent = bytesSent;
	}

	public long getBytesReceived() {
		return bytesReceived;
	}

	public void setBytesReceived(long bytesReceived) {
		this.bytesReceived = bytesReceived;
	}

	public long getProcessingTime() {
		return processingTime;
	}

	public void setProcessingTime(long processingTime) {
		this.processingTime = processingTime;
	}

	public long getMaxTime() {
		return maxTime;
	}

	public void setMaxTime(long maxTime) {
		this.maxTime = maxTime;
	}

	public String getMaxRequestUri() {
		return maxRequestUri;
	}

	public void setMaxRequestUri(String maxRequestUri) {
		this.maxRequestUri = maxRequestUri;
	}

	public int getRequestCount() {
		return requestCount;
	}

	public void setRequestCount(int requestCount) {
		this.requestCount = requestCount;
	}

	public int getErrorCount() {
		return errorCount;
	}

	public void setErrorCount(int errorCount) {
		this.errorCount = errorCount;
	}

	public String getWorkerThreadName() {
		return workerThreadName;
	}

	public ObjectName getRpName() {
		return rpName;
	}

	public long getLastRequestProcessingTime() {
		return lastRequestProcessingTime;
	}

	public void setWorkerThreadName(String workerThreadName) {
		this.workerThreadName = workerThreadName;
	}

	public void setRpName(ObjectName rpName) {
		this.rpName = rpName;
	}

	public void setLastRequestProcessingTime(long lastRequestProcessingTime) {
		this.lastRequestProcessingTime = lastRequestProcessingTime;
	}


如果你使用的是Java Web开发的Servlet技术,并且在Java代码将Key为"data",Value为1的数据放入了HttpServletRequest对象(例如通过HttpServletRequest的setAttribute()方法),那么在org.apache.coyoteresponse是无法直接找到这个数据的。 HttpServletRequest对象是在Servlet容器创建的,它用于封装HTTP请求消息。在Servlet的doXXX()方法,我们可以通过HttpServletRequest对象获取请求参数、请求头等信息,并向HttpServletRequest对象添加属性、设置响应头等信息。 HttpServletResponse对象则用于封装HTTP响应消息。在Servlet的doXXX()方法,我们可以通过HttpServletResponse对象向响应添加响应头、设置响应码等信息,并向HttpServletResponse对象写入响应内容。 在Tomcat,org.apache.coyote.Response对象则用于封装底层Socket的读写操作。它会将处理完毕的HTTP请求和HTTP响应消息通过底层Socket通道进行读写。在org.apache.coyote.Response对象,可以获取到响应头、响应状态码等信息,但是HttpServletRequest对象的属性是无法直接获取到的。 如果你希望在响应返回"data"属性的值,可以在Servlet的doXXX()方法通过HttpServletResponse对象将值写入到响应体。例如,以下代码可以将"data"属性的值写入到响应体: ```java protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 获取"data"属性的值 Object data = request.getAttribute("data"); // 设置响应类型和编码 response.setContentType("text/plain;charset=UTF-8"); // 获取输出流并输出数据 PrintWriter out = response.getWriter(); out.println(data); out.flush(); // 必须调用flush方法将数据刷出缓冲区 out.close(); } ``` 在上面的代码,我们首先通过HttpServletRequest对象的getAttribute()方法获取"data"属性的值,然后通过HttpServletResponse对象的getWriter()方法获取输出流,并将"data"属性的值输出到输出流。最后,我们要记得调用flush()方法将数据刷出缓冲区,并关闭输出流。这样,响应就会包含一个响应主体,它的内容就是"data"属性的值。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值