How Tomcat Works 4

本文详细解析了Tomcat中的流水线和阀门原理,解释了它们的工作模式和责任链模式,并通过标准PipelineValveContext类的实现展示了阀门如何在请求和响应对象上操作。同时,介绍了如何通过service.xml文件配置阀门类,以及Tomcat错误处理页面的实现逻辑。
摘要由CSDN通过智能技术生成

本系列第四节重点讲讲tomcat中的流水线和阀门。

如果你了解servlet的过滤器那么理解流水线会容易得多,因为他们两个的原理是一样的。一个流水线就像是一个过滤链,上面的阀门就和过滤器一样,在tomcat中阀门可以操作传递给他们的Request和Resopnse对象。实际上这两种工作模式都是基于责任链模式实现的,如果不清楚责任链模式可以去网上查一查。

tomcat中的ValveBase就是表示的流水线上的阀门类,其中最重要的一个方法为:

//核心方法invoke,里面主要是处理request和response的逻辑
//当然还有重要的一步,调用链中的下一个处理节点,典型的责任链
//是由sucessor保存下一个节点来完成的,tomcat中抽象出ValveContext
//存储所有的valve,只需要调用context.invokeNext方法即可
public abstract void invoke(Request request, Response response,
                                ValveContext context)
        throws IOException, ServletException;
ValveContext类似下面:

/**
*valvecontext的核心方法,调用下一个value,tomcat中StandardPipelineValveContext
实现了ValveContext接口
*/
public void invokeNext(Request request, Response response)
        throws IOException, ServletException;
StandardPipelineValveContext类为StandardPipeline的内部类,pipeline中的Valve valves[]字段存储了所有的valve。这样StandardPipelineValveContext便可以使用pipeline中的valves字段了。StandardPipelineValveContext类如下:

protected class StandardPipelineValveContext
        implements ValveContext {


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

	//表示下一步要调用的valve
        protected int stage = 0;


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


        /**
          * Return descriptive information about this ValveContext 
          * implementation.
          */
        public String getInfo() {
            return info;
        }


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


        /**
         * Cause the <code>invoke()</code> method of the next Valve that is 
         * part of the Pipeline currently being processed (if any) to be 
         * executed, passing on the specified request and response objects 
         * plus this <code>ValveContext</code> instance.  Exceptions thrown by
         * a subsequently executed Valve (or a Filter or Servlet at the 
         * application level) will be passed on to our caller.
         *
         * If there are no more Valves to be executed, an appropriate
         * ServletException will be thrown by this ValveContext.
	 *	
         */
        public void invokeNext(Request request, Response response)
            throws IOException, ServletException {
		
	     //subscript表示当前要调用的valve
            int subscript = stage;
            stage = stage + 1;

            // Invoke the requested Valve for the current request thread
		//从valves集合中取出一个valve调用它的invoke方法
            if (subscript < valves.length) {
                valves[subscript].invoke(request, response, this);
            } else if ((subscript == valves.length) && (basic != null)) {
		//最后调用basic的invoke方法
                basic.invoke(request, response, this);
            } else {
                throw new ServletException
                    (sm.getString("standardPipeline.noValve"));
            }
        }
    }

来看一个非常熟悉的tomcat错误处理页面,错误页面处理都是由tomcat中的ErrorReportValve类负责输出,主要的逻辑如下:

/**
     * Invoke the next Valve in the sequence. When the invoke returns, check 
     * the response state, and output an error report is necessary.
     *
     * @param request The servlet request to be processed
     * @param response The servlet response to be created
     * @param context The valve context used to invoke the next valve
     *  in the current processing pipeline
     *
     * @exception IOException if an input/output error occurs
     * @exception ServletException if a servlet error occurs
     */
    public void invoke(Request request, Response response,
                       ValveContext context)
        throws IOException, ServletException {

        // Perform the request
        context.invokeNext(request, response);

        ServletRequest sreq = (ServletRequest) request;
        Throwable throwable = 
            (Throwable) sreq.getAttribute(Globals.EXCEPTION_ATTR);

        ServletResponse sresp = (ServletResponse) response;
        if (sresp.isCommitted()) {
            return;
        }
	//检查处理过程是否抛出了异常
        if (throwable != null) {

            // The response is an error
	    //如果有异常设置错误输出
            response.setError();

            // Reset the response (if possible)
            try {
		//重置响应
                sresp.reset();
            } catch (IllegalStateException e) {
                ;
            }

            ServletResponse sresponse = (ServletResponse) response;
            if (sresponse instanceof HttpServletResponse)
                ((HttpServletResponse) sresponse).sendError
                    (HttpServletResponse.SC_INTERNAL_SERVER_ERROR);

        }

        response.setSuspended(false);
		//报告错误
        try {
            report(request, response, throwable);
        } catch (Throwable tt) {
            tt.printStackTrace();
        }
    }
实际上tomcat中的请求和响应就是被流水线上的一个个valve层层处理的,最后提一点,可以通过service.xml文件配置我们需要的valve类似下面:

<!-- Define the default virtual host
           Note: XML Schema validation will not work with Xerces 2.2.
       -->
      <Host name="localhost"  appBase="webapps"
            unpackWARs="true" autoDeploy="true"
            xmlValidation="false" xmlNamespaceAware="false">

        <!-- SingleSignOn valve, share authentication between web applications
             Documentation at: /docs/config/valve.html -->
        <!--
        <Valve className="org.apache.catalina.authenticator.SingleSignOn" />
        -->

        <!-- Access log processes all example.
             Documentation at: /docs/config/valve.html -->
        <!--
        <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"  
               prefix="localhost_access_log." suffix=".txt" pattern="common" resolveHosts="false"/>
        -->
通过配置文件配置valve会被自动的组织到valves[]中,可以想象下是在解析xml文件的过程中完成的addValve动作。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值