Tomcat源码4

今天来看看Tomcat中的Request&Response设计结构,这里主要分析Request的结构,至于Response一样的思想!引用网上的一幅图!

是不是看起来很杂,看看How tomcat work提供的一幅图,相对比较简单!




作为web container,Tomcat还需要在request中保存许多内部信息及使用方法,这些信息和方法不应该暴露给web开发人员,否则会造成不必要的麻烦。
那么,Tomcat中是如何实现只向开发人员提供有限接口,而内部提供更多接口的呢?
ServletRequest: 这个接口来自javax包,是JSP Spec中定义必须要实现的。
Request: Catalina内部的Request接口,为ServletRequest提供了许多补充方法,供 Catalina内部使用。
HttpServletRequest: 来自javax包,是JSP Spec中定义作为Http的request必须要实现的。
HttpRequest: Catalina内部的Request接口,为HttpServletRequest提供了许多补充方法,供Catalina内部使用。

Default Pattern缺省模式,实际上这本身并不能算是一种模式,最多只能是一种编程方法,对于接口的所有子类,提供一个默认实现,在这里就是RequestBase及HttpRequestBase所做的工作,HttpRquestBase向HttpRquestImpl提供了HttpRequest和HttpServletRequest的默认实现。这样以后添加新的继承就只需要实现几个方法。

Adapter Pattern适配器模式,我们已经知道HttpRequestImpl中包含了HttpRequest和HttpServletRequest定义的所有方法的实现,然而对于Catalina组件,他们并不需要知道任何关于HttpServletRequest接口中定义的内容。因此,我们可以通过适配器模式将任何继承了HttpRequest和HttpServletRequest的类封装起来,并只提供HttpRequest提供的接口(可以看到HttpRequestWrapper继承HttpRequest)。这怎么理解呢?
首先从适配器模式的原理入手,(引用java与模式的一句话)适配器的作用就是做接口的转换。那么这里的转换是怎么体现出来的呢?从上面的图中可以看出HttpRequestBase与HttpRequestImpl等类都是既实现了HttpRequest接口又实现了HttpServletRequest接口,但是对于Catalina组件,它们并不需要用到HttpServletRequest的方法。看HttpquestWrapper的源码实现你就能明白了!
org.apache.catalina Interface HttpRequest
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


package org.apache.catalina.connector;


import java.security.Principal;
import java.util.Locale;
import javax.servlet.http.Cookie;
import org.apache.catalina.HttpRequest;


/**
 * Abstract convenience class that wraps a Catalina-internal <b>HttpRequest</b>
 * object.  By default, all methods are delegated to the wrapped request,
 * but subclasses can override individual methods as required to provide the
 * functionality that they require.
 *
 * @author Craig R. McClanahan
 * @version $Revision: 466595 $ $Date: 2006-10-21 23:24:41 +0100 (Sat, 21 Oct 2006) $
 * @deprecated
 */

public abstract class HttpRequestWrapper
    extends RequestWrapper
    implements HttpRequest {


    // ----------------------------------------------------------- Constructors


    /**
     * Construct a wrapper for the specified request.
     *
     * @param request The request to be wrapped
     */
    public HttpRequestWrapper(HttpRequest request) {

        super(request);

    }


    // --------------------------------------------------------- Public Methods


    /**
     * Add a Cookie to the set of Cookies associated with this Request.
     *
     * @param cookie The new cookie
     */
    public void addCookie(Cookie cookie) {

        ((HttpRequest) request).addCookie(cookie);

    }


    /**
     * Add a Header to the set of Headers associated with this Request.
     *
     * @param name The new header name
     * @param value The new header value
     */
    public void addHeader(String name, String value) {

        ((HttpRequest) request).addHeader(name, value);

    }


    /**
     * Add a Locale to the set of preferred Locales for this Request.  The
     * first added Locale will be the first one returned by getLocales().
     *
     * @param locale The new preferred Locale
     */
    public void addLocale(Locale locale) {

        ((HttpRequest) request).addLocale(locale);

    }


    /**
     * Clear the collection of Cookies associated with this Request.
     */
    public void clearCookies() {

        ((HttpRequest) request).clearCookies();

    }


    /**
     * Clear the collection of Headers associated with this Request.
     */
    public void clearHeaders() {

        ((HttpRequest) request).clearHeaders();

    }


    /**
     * Clear the collection of Locales associated with this Request.
     */
    public void clearLocales() {

        ((HttpRequest) request).clearLocales();

    }


    /**
     * Set the authentication type used for this request, if any; otherwise
     * set the type to <code>null</code>.  Typical values are "BASIC",
     * "DIGEST", or "SSL".
     *
     * @param type The authentication type used
     */
    public void setAuthType(String type) {

        ((HttpRequest) request).setAuthType(type);

    }


    /**
     * Set the context path for this Request.  This will normally be called
     * when the associated Context is mapping the Request to a particular
     * Wrapper.
     *
     * @param path The context path
     */
    public void setContextPath(String path) {

        ((HttpRequest) request).setContextPath(path);

    }


    /**
     * Set the HTTP request method used for this Request.
     *
     * @param method The request method
     */
    public void setMethod(String method) {

        ((HttpRequest) request).setMethod(method);

    }


    /**
     * Set the query string for this Request.  This will normally be called
     * by the HTTP Connector, when it parses the request headers.
     *
     * @param query The query string
     */
    public void setQueryString(String query) {

        ((HttpRequest) request).setQueryString(query);

    }


    /**
     * Set the path information for this Request.  This will normally be called
     * when the associated Context is mapping the Request to a particular
     * Wrapper.
     *
     * @param path The path information
     */
    public void setPathInfo(String path) {

        ((HttpRequest) request).setPathInfo(path);

    }


    /**
     * Set a flag indicating whether or not the requested session ID for this
     * request came in through a cookie.  This is normally called by the
     * HTTP Connector, when it parses the request headers.
     *
     * @param flag The new flag
     */
    public void setRequestedSessionCookie(boolean flag) {

        ((HttpRequest) request).setRequestedSessionCookie(flag);

    }


    /**
     * Set the requested session ID for this request.  This is normally called
     * by the HTTP Connector, when it parses the request headers.
     *
     * @param id The new session id
     */
    public void setRequestedSessionId(String id) {

        ((HttpRequest) request).setRequestedSessionId(id);

    }


    /**
     * Set a flag indicating whether or not the requested session ID for this
     * request came in through a URL.  This is normally called by the
     * HTTP Connector, when it parses the request headers.
     *
     * @param flag The new flag
     */
    public void setRequestedSessionURL(boolean flag) {

        ((HttpRequest) request).setRequestedSessionURL(flag);

    }


    /**
     * Set the unparsed request URI for this Request.  This will normally be
     * called by the HTTP Connector, when it parses the request headers.
     *
     * @param uri The request URI
     */
    public void setRequestURI(String uri) {

        ((HttpRequest) request).setRequestURI(uri);

    }


    /**
     * Set the servlet path for this Request.  This will normally be called
     * when the associated Context is mapping the Request to a particular
     * Wrapper.
     *
     * @param path The servlet path
     */
    public void setServletPath(String path) {

        ((HttpRequest) request).setServletPath(path);

    }


    /**
     * Set the Principal who has been authenticated for this Request.  This
     * value is also used to calculate the value to be returned by the
     * <code>getRemoteUser()</code> method.
     *
     * @param principal The user Principal
     */
    public void setUserPrincipal(Principal principal) {

        ((HttpRequest) request).setUserPrincipal(principal);

    }

}
我们说过HttpRequestBase和HttpRequestImpl类都是实现了HttpRequest和HttpServletRequest接口的,那么加入现在把HttpRequestBase实例或者是把HttpRequestImpl实例传入到HttpRequestWrapper类中,那么HttpRequestWrapper类就拥有了它们的实例。但是对于HttpRequestWrapper来说,HttpRequestBase和HttpRequestImpl实例暴露出来的接口太多了,也就是一些Catalina组件没必要用到的接口,那么这时候就把ttpRequestWrapper设计成适配器类,通过实现接口的转换,把HttpRequestBase和HttpRequestImpl要用到的接口重新封装一下,就实现了接口的转换了。

3,Facade Pattern门面模式,门面模式将内部复杂的实现隐藏起来,并提供一个简单的接口给外部的用户使用。在这里,HttpRequestFacade类将只提供HttpServletRequest中定义的方法给web开发人员。 这个模式很金典,我也是最近才掌握的!其实在Tomcat的设计中,我个人觉得它的适配器模式和门面模式设计感觉都差不多。但是实际中,这两种模式还是有一些区别的。而RequestFacade和HttpRequestFacade都是门面模式设计出来的外观类。
简单说说这样的好处,上面我们说过HttpRequestImpl类都是实现了HttpRequest和HttpServletRequest接口,也就是说HttpRequestImpl暴露了HttpRequest和HttpServletRequest接口里面的方法,但对于实际开发,我们不希望把HttpRequest接口里面定义的方法也暴露给开发人员,那么就找了一个HttpRequestFacade来一些不像暴露出来的接口给隐藏掉。我们来看看HttpRequestFacade的实现!
org.apache.catalina Interface HttpRequestFacade
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


package org.apache.catalina.connector;


import java.util.Enumeration;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpSession;
import org.apache.catalina.HttpRequest;
import org.apache.catalina.session.StandardSessionFacade;


/**
 * Facade class that wraps a Catalina-internal <b>HttpRequest</b>
 * object.  All methods are delegated to the wrapped request.
 *
 * @author Remy Maucherat
 * @version $Revision: 466595 $ $Date: 2006-10-21 23:24:41 +0100 (Sat, 21 Oct 2006) $
 */

public final class HttpRequestFacade
    extends RequestFacade
    implements HttpServletRequest {


    // ----------------------------------------------------------- Constructors


    /**
     * Construct a wrapper for the specified request.
     *
     * @param request The request to be wrapped
     */
    public HttpRequestFacade(HttpRequest request) {
        super(request);
    }


    // --------------------------------------------- HttpServletRequest Methods


    public String getAuthType() {
        return ((HttpServletRequest) request).getAuthType();
    }


    public Cookie[] getCookies() {
        return ((HttpServletRequest) request).getCookies();
    }


    public long getDateHeader(String name) {
        return ((HttpServletRequest) request).getDateHeader(name);
    }


    public String getHeader(String name) {
        return ((HttpServletRequest) request).getHeader(name);
    }


    public Enumeration getHeaders(String name) {
        return ((HttpServletRequest) request).getHeaders(name);
    }


    public Enumeration getHeaderNames() {
        return ((HttpServletRequest) request).getHeaderNames();
    }


    public int getIntHeader(String name) {
        return ((HttpServletRequest) request).getIntHeader(name);
    }


    public String getMethod() {
        return ((HttpServletRequest) request).getMethod();
    }


    public String getPathInfo() {
        return ((HttpServletRequest) request).getPathInfo();
    }


    public String getPathTranslated() {
        return ((HttpServletRequest) request).getPathTranslated();
    }


    public String getContextPath() {
        return ((HttpServletRequest) request).getContextPath();
    }


    public String getQueryString() {
        return ((HttpServletRequest) request).getQueryString();
    }


    public String getRemoteUser() {
        return ((HttpServletRequest) request).getRemoteUser();
    }


    public boolean isUserInRole(String role) {
        return ((HttpServletRequest) request).isUserInRole(role);
    }


    public java.security.Principal getUserPrincipal() {
        return ((HttpServletRequest) request).getUserPrincipal();
    }


    public String getRequestedSessionId() {
        return ((HttpServletRequest) request).getRequestedSessionId();
    }


    public String getRequestURI() {
        return ((HttpServletRequest) request).getRequestURI();
    }


    public StringBuffer getRequestURL() {
        return ((HttpServletRequest) request).getRequestURL();
    }


    public String getServletPath() {
        return ((HttpServletRequest) request).getServletPath();
    }


    public HttpSession getSession(boolean create) {
        HttpSession session =
            ((HttpServletRequest) request).getSession(create);
        if (session == null)
            return null;
        else
            return new StandardSessionFacade(session);
    }


    public HttpSession getSession() {
        return getSession(true);
    }


    public boolean isRequestedSessionIdValid() {
        return ((HttpServletRequest) request).isRequestedSessionIdValid();
    }


    public boolean isRequestedSessionIdFromCookie() {
        return ((HttpServletRequest) request).isRequestedSessionIdFromCookie();
    }


    public boolean isRequestedSessionIdFromURL() {
        return ((HttpServletRequest) request).isRequestedSessionIdFromURL();
    }


    public boolean isRequestedSessionIdFromUrl() {
        return ((HttpServletRequest) request).isRequestedSessionIdFromURL();
    }


}

假如这时把HttpRequestImpl实例传入到HttpRequestFacade类来,那么在HttpRequestFacade类中就去访问HttpRequestImpl实例的任何方法,但是对于我们的要求是不能把HttpRequestImpl的所有接口都暴露出来,那么这时利用门面模式把HttpRequestFacade设计成一个外观类,并且去实现HttpServletRequest接口,那么它就只暴露了HttpServletRequest接口里面的方法而已,而巧妙的把HttpRequest接口的方法给隐藏起来了!而且HttpRequestImpl是不对外公开的!

引用别人总结的话:适配器着重于将一个接口转换成另一个接口,门面模式则着重于将复杂的内部实现隐藏起来,提供一个简单的通用接口。

其实上面的这两种模式,在多线程并发也有很大的作用,具体我会在后面的多线程中进行总结!

好了,设计模式的东西就讲到这里了,下一节看看如果具体去实现HttpRequestImpl和HttpResponseImpl的方法。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值