`
gearever
  • 浏览: 149311 次
社区版块
存档分类
最新评论

tomcat架构分析(valve源码导读)

阅读更多
出处:http://gearever.iteye.com

源码面前,了无秘密
                             ----侯捷
在tomcat架构分析(valve机制)(http://gearever.iteye.com/blog/1536022)里已经对valve的机制做了分析。现在通过源码来加深下理解。侯捷说过,源码面前,了无秘密。通过这些代码,可以看到在tomcat中我们经常碰到的一些现象或配置是怎么实现的。
StandardEngineValve
看一下StandardEngineValve的调用逻辑;
    public final void invoke(Request request, Response response)
        throws IOException, ServletException {

        // 定位host
        Host host = request.getHost();
        if (host == null) {
            ......
            return;
        }

        // 调用host的第一个valve
        host.getPipeline().getFirst().invoke(request, response);

    }

可以清晰的看到,根据request定位到可以处理的host对象,同时,开始从头调用host里的pipeline上的valve。
StandardHostValve
看一下StandardHostValve的调用逻辑;
    public final void invoke(Request request, Response response)
        throws IOException, ServletException {

        // 定位context
        Context context = request.getContext();
        if (context == null) {
            ......
            return;
        }

        ......

        // 调用context的第一个valve
        context.getPipeline().getFirst().invoke(request, response);

        // 更新session
        if (Globals.STRICT_SERVLET_COMPLIANCE) {
            request.getSession(false);
        }

        // Error page processing
        response.setSuspended(false);

        //如果有抛异常或某个HTTP错误,导向响应的配置页面
        Throwable t = (Throwable) request.getAttribute(Globals.EXCEPTION_ATTR);

        if (t != null) {
            throwable(request, response, t);
        } else {
            status(request, response);
        }

        // Restore the context classloader
        Thread.currentThread().setContextClassLoader
            (StandardHostValve.class.getClassLoader());

    }

可以清晰的看到,注释部分里根据request定位到可以处理的context对象,同时,开始从头调用context里的pipeline上的valve。在调用完context的所有的valve之后(当然也是context调用完其对应的wrapper上的所有valve之后),蓝色部分显示了拿到response对象时可以做的处理。
熟悉tomcat的可能有配置错误信息的经验,例如;
<error-page>
  <error-code>404</error-code>
  <location>/error.jsp</location>
 </error-page>

它就是为了在用户访问资源出现HTTP 404错误时,将访问重定向到一个统一的错误页面。这样做一是为了美观,另一个主要作用是不会将一些具体的错误信息例如java抛异常时的栈信息暴露给用户,主要还是出于安全的考虑。 上述代码中的注释部分就是实现这个重定向功能。

StandardContextValve
看一下StandardContextValve的调用逻辑;其代码比较多,只贴一些比较核心的吧。
    public final void invoke(Request request, Response response)
        throws IOException, ServletException {

        ......

        // 定位wrapper
        Wrapper wrapper = request.getWrapper();
        if (wrapper == null) {
            notFound(response);
            return;
        } else if (wrapper.isUnavailable()) {
            ......
        }

        // Normal request processing
        //web.xml中配置web-app/listener/listener-class
        Object instances[] = context.getApplicationEventListeners();

        ServletRequestEvent event = null;

        //响应request初始化事件,具体的响应listener是可配置的 
        ......
        //调用wrapper的第一个valve
        wrapper.getPipeline().getFirst().invoke(request, response); 

        //响应request撤销事件,具体的响应listener是可配置的 
        ......             
    }

可以清晰的看到,注释部分里根据request定位到可以处理的wrapper对象,同时,开始从头调用wrapper里的pipeline上的valve。 需要注意的是,这里在调用wrapper的valve前后,分别有响应request初始化及撤销事件的逻辑,tomcat有一整套事件触发体系,这里限于篇幅就不阐述了。有时间专门说。
StandardWrapperValve
看一下StandardWrapperValve的调用逻辑;其代码比较多,只贴一些比较核心的吧;
    public final void invoke(Request request, Response response)
        throws IOException, ServletException {
    	
    	......
        requestCount++;
        //定位wrapper
        StandardWrapper wrapper = (StandardWrapper) getContainer();
        Servlet servlet = null;
        Context context = (Context) wrapper.getParent();
        
        ......

        // Allocate a servlet instance to process this request
        try {
            if (!unavailable) {
            	//加载servlet
                servlet = wrapper.allocate();                
            }
        } catch (UnavailableException e) {
            ......
        } 
        ......
        // 根据配置建立一个filter-servlet的处理链表,servlet在链表的尾端
        ApplicationFilterFactory factory =
            ApplicationFilterFactory.getInstance();
        ApplicationFilterChain filterChain =
            factory.createFilterChain(request, wrapper, servlet);
        // Reset comet flag value after creating the filter chain
        request.setComet(false);

        // Call the filter chain for this request
        // NOTE: This also calls the servlet's service() method
        try {
            String jspFile = wrapper.getJspFile();
            if (jspFile != null)
            	request.setAttribute(Globals.JSP_FILE_ATTR, jspFile);
            else
            	request.removeAttribute(Globals.JSP_FILE_ATTR);
            if ((servlet != null) && (filterChain != null)) {
                // Swallow output if needed
                if (context.getSwallowOutput()) {
                    try {
                        SystemLogHandler.startCapture();
                        if (comet) {
                            filterChain.doFilterEvent(request.getEvent());
                            request.setComet(true);
                        } else {
                            //调用filter-servlet链表
                            filterChain.doFilter(request.getRequest(), 
                                    response.getResponse());
                        }
                    } finally {
                        String log = SystemLogHandler.stopCapture();
                        if (log != null && log.length() > 0) {
                            context.getLogger().info(log);
                        }
                    }
                } else {
                    if (comet) {
                        request.setComet(true);
                        filterChain.doFilterEvent(request.getEvent());
                    } else {
                        //调用filter-servlet链表
                        filterChain.doFilter
                            (request.getRequest(), response.getResponse());
                    }
                }

            }
            request.removeAttribute(Globals.JSP_FILE_ATTR);
        } catch (ClientAbortException e) {
        	request.removeAttribute(Globals.JSP_FILE_ATTR);
            throwable = e;
            exception(request, response, e);
        } 
        ......
    }

可以清晰的看到,注释部分里,先是能拿到相应的wrapper对象;然后完成加载wrapper对象中的servlet,例如如果是jsp,将完成jsp编译,然后加载servlet等;再然后,根据配置生成一个filter栈,通过执行栈,调用完所有的filter之后,就调用servlet,如果没有配置filter,就直接调用servlet,生成filter栈是通过request的URL模式匹配及servlet名称来实现的,具体涉及的东西在tomcat的servlet规范实现中再阐述吧。
以上,完成了一整套servlet调用的过程。通过上面的阐述,可以看见valve是个很灵活的机制,通过它可以实现很大的扩展。
Valve的应用及定制化
Tomcat除了提供上面提到的几个标准的valve实现外,也提供了一些用于调试程序的valve的实现。实现valve需要继承org.apache.catalina.valves.ValveBase基类。 以RequestDumperValve为例,
引用
org.apache.catalina.valves.RequestDumperValve

RequestDumperValve是打印出request及response信息的valve。其实现方法为:
public void invoke(Request request, Response response) 
				throws IOException, ServletException { 

		Log log = container.getLogger(); 

		// Log pre-service information 
		log.info("REQUEST URI =" + request.getRequestURI()); 
		...... 
		log.info(" queryString=" + request.getQueryString()); 
		...... 
		log.info("-------------------------------------------------------"); 
		
		// 调用下一个valve
		getNext().invoke(request, response); 
		
		// Log post-service information 
		log.info("-------------------------------------------------------"); 
		...... 
		log.info(" contentType=" + response.getContentType()); 
		Cookie rcookies[] = response.getCookies(); 
		for (int i = 0; i < rcookies.length; i++) { 
		    log.info(" cookie=" + rcookies[i].getName() + "=" + 
				rcookies[i].getValue() + "; domain=" + 
				rcookies[i].getDomain() + "; path=" + rcookies[i].getPath()); 
		} 
		String rhnames[] = response.getHeaderNames(); 
		for (int i = 0; i < rhnames.length; i++) { 
		    String rhvalues[] = response.getHeaderValues(rhnames[i]); 
		    for (int j = 0; j < rhvalues.length; j++) 
			log.info(" header=" + rhnames[i] + "=" + rhvalues[j]); 			
		}
		log.info(" message=" + response.getMessage()); 
		log.info("========================================================"); 

}

可以很清晰的看出,它打印出了request及response的信息,其中红色部分显示它调用valve链表中的下一个valve。我们可以这样配置它;
<Host name="localhost"  appBase="webapps"
            unpackWARs="true" autoDeploy="true"
            xmlValidation="false" xmlNamespaceAware="false">
      <Valve className="org.apache.catalina.valves.RequestDumperValve"/>
      <Context path="/my" docBase=" /usr/local/tomcat/backup/my" >          	
      </Context>
      <Context path="/my2" docBase=" /usr/local/tomcat/backup/my" >          	
      </Context>
</Host>

这样,只要访问此host下的所有context,都会打印出调试信息。 Valve的应用有很多,例如cluster,SSO等,会有专门一章来讲讲。
分享到:
评论
2 楼 tmj_159 2013-01-21  
不错,俺准备今天全部看完
1 楼 飞天奔月 2012-05-24  
楼主对tomcat 研究很深刻

我接触的主要是tomcat rss关注学习楼主的帖子

相关推荐

    tomcat 架构 分析

    在深入分析Tomcat的架构之前,需要了解Tomcat是Apache Jakarta项目中的一个核心项目,是一个免费的开源Servlet容器。它主要用于作为独立服务器或集成到Web服务器中,如Apache和IIS等。作为Web服务器,Tomcat负责解析...

    tomcat架构的源码分析

    ### Tomcat架构的源码分析 #### 一、Tomcat的架构概述 Tomcat作为一款广泛使用的开源Java Servlet容器,其内部架构设计简洁而高效。本文档将对Tomcat的架构进行详细介绍,并从源码层面深入分析其核心组成部分。...

    「Tomcat源码剖析」.pdf

    Tomcat源码剖析 : 整体架构 层层分析 源码解析 架构分析 (Http服务器功能:Socket通信(TCP/IP)、解析Http报文 Servlet容器功能:有很多Servlet(自带系统级Servlet+自定义Servlet),Servlet处理具体的业务逻辑...

    tomcat源码+文档pdf+源码解析

    这个资源包包含了Tomcat的源码、文档以及源码解析,对于深入理解Tomcat的工作原理、优化应用性能以及进行二次开发具有极大的帮助。 首先,让我们深入探讨Tomcat的源码。源码是软件的基石,通过阅读源码,我们可以...

    Tomcat架构解析文档.zip

    【Java面试必备】Tomcat架构解析 Tomcat作为一款开源的、基于Java的Web应用服务器,是许多初学者和开发者入门Java Web应用的首选。它轻量级、高效且易于管理,广泛应用于小型到中型企业级应用。在面试中,对Tomcat...

    tomcat 源码分析系列文档

    7. "tomcat源码分析之一架构.pdf":可能涵盖了Tomcat的整体架构,包括Catalina、 Coyote、Jasper等主要模块的功能和相互关系。 8. "HTTP协议详解.pdf":作为基础,此文档提供了HTTP协议的详细讲解,帮助读者理解...

    tomcat6源码分析

    《Tomcat6源码分析——深入理解Web服务器的运行机制》 Tomcat6作为Apache软件基金会的Jakarta项目的一部分,是一款广泛使用的Java Servlet容器,它实现了Java Servlet和JavaServer Pages(JSP)规范,为开发和部署...

    tomcat架构解析-高清-完整

    本书只是从架构设计上,对Tomcat的各组件进行了概念性讲解,如果你想阅读Tomcat的源码,本书的内容会让你更容易了解Tomcat的组件结构、设计方案,更容易去由概要到具体的熟悉Tomcat各组件的实现。 其次,本书不局限...

    最新设计模式超级详解+Tomcat架构源码分析+Spring源码分析 资深级设计模型课程

    Spring源码分析,web源码分析,Tomcat架构源码分析都是非常深入的源码级课程,期待研究设计模式和深入学习源码内功的朋友们,一定要仔细的学习研究。 (0);目录中文件数:1个 ├─3.代码.zip (1)\1.笔记;目录中文...

    Tomcat系统架构分析

    Tomcat作为Apache软件基金会旗下的一个开源...通过深入分析Tomcat系统架构,可以更好地理解其工作原理,从而在实际应用中根据需要进行定制和优化。无论是进行开发工作还是系统配置,对Tomcat架构的掌握都显得至关重要。

    Tomcat架构介绍与源码分析(含插件开发)

    ?通过剖析TOMCAT启动及请求流程来了解TOMCAT核心组件及动作原理 ...通过剖析核心组件的源码来深入理解TOMCAT内部原理?介绍实际项目中开发的TOMCAT插件,附源码?了解uml图绘制方法及工具介绍,并介绍常见开源框架的uml图

    tomcat源码

    Apache Tomcat源码分析 Apache Tomcat是一款广泛应用的开源Java Servlet容器,它是Java EE Web应用程序的标准实现。Tomcat源码的深入理解对于Java Web开发者来说是至关重要的,它可以帮助我们了解HTTP服务器的工作...

    tomcat架构解析_PDF电子书下载 高清 带索引书签目录_刘光瑞(著)

    《Tomcat架构解析》这本书由刘光瑞撰写,由人民邮电出版社出版,是一本深入探讨Tomcat服务器架构的专业书籍。Tomcat作为Apache软件基金会的项目之一,是世界上最流行的Java应用服务器,尤其在轻量级Web应用领域,其...

    java学习CS架构网络编程;简易模拟tomcat服务器项目源码.zip

    简易模拟tomcat服务器项目源码java学习CS架构网络编程;简易模拟tomcat服务器项目源码java学习CS架构网络编程;简易模拟tomcat服务器项目源码java学习CS架构网络编程;简易模拟tomcat服务器项目源码java学习CS架构...

    tomcat7源码下载

    《深入剖析Tomcat7源码》 Tomcat7是一款广泛使用的开源Java Servlet容器,它实现了Java EE中的Web应用服务器标准,尤其是Servlet和JSP规范。源码下载是开发者深入理解其内部工作原理的重要途径,本篇文章将围绕...

    tomcat 架构分析(概览)

    以下是关于Tomcat架构的详细分析。 首先,核心架构模块是Tomcat的基础,包括Server、Service、Engine、Host和Context以及Wrapper等。Server作为最顶层的组件,包含了多个Service。Service是Tomcat对外提供服务的...

    tomcat 架构解析和优化。pdf

    《Tomcat架构解析与优化》一书主要涵盖了Apache Tomcat服务器的基础架构、工作原理以及性能调优策略。Tomcat作为一款广泛使用的Java Servlet容器,它的高效运行和优化对于任何Java Web应用都至关重要。 首先,...

    Tomcat 10 软件及其源码

    版本:apache-tomcat-10.1.23 Tomcat 10 是 Apache Tomcat 的一个版本,它引入了一些新的功能和改进。以下是一些关键的新增功能: ...8. 改进的 Metrics 支持:提供了更好的方式来监控和分析应用性能。

    tomcat7源码

    源码分析是提升开发者对服务器内部运作机制理解的重要途径,尤其对于Tomcat这样的核心组件,源码的学习能够帮助我们更深入地理解Web应用的部署、运行以及性能优化。 首先,我们要了解Tomcat的架构。Tomcat7基于...

Global site tag (gtag.js) - Google Analytics