分享

Tomcat源码分析

 燮羽 2010-12-02

1.Tomcat共有五类ClassLoader: 
  commonLoader: 
      用于加载公共jar包,比如servlet规范包,servlet-api.jar,位于/common 
  catalinaLoader: 
      用于加载Tomcat的实现jar包,比如catalina.jar,位于/server 
  sharedLoader: 
      用于加载所有应用的共享jar包,比如struts核心包就可以放在下面,位于/shared 
  webappClassLoader 
      用于加载web应用下的class,一个web应用有一个webappClassLoader 
  JasperLoader 
      用于加载web应用下由jsp编译后的servlet,一个web应用有一个JasperLoader 

它们的父子代理关系如下: 

                     JREClassLoader 
                               | 
                     commonLoader 
                     /                       \  
          catalinaLoader        sharedLoader   
                                              /                      \ 
                          webappClassLoader ........webappClassLoader 
                                     |                                         | 
                           JasperLoader                   JasperLoader 

2.WebAppClassLoader加载策略 
  1.首先判断class是否已经加载,若已加载,则直接返回,若没加载,则进行第2步 
  2.使用系统加载器加载class,若加载成功,则返回,若失败,则进行第3步 
  3.如果webAppClassLoader设置了代理模式,则用父加载器进行加载;否则直接加载 
  4.如果webAppClassLoader未设置代理模式,则自己先加载,失败后再使用父加载器加载 

WebappClassLoader类loadClass方法

Java代码 
  1. public Class loadClass(String name, boolean resolve)  
  2.         throws ClassNotFoundException {  
  3.   
  4.         if (log.isDebugEnabled())  
  5.             log.debug("loadClass(" + name + ", " + resolve + ")");  
  6.         Class clazz = null;  
  7.   
  8.         // Log access to stopped classloader  
  9.         if (!started) {  
  10.             try {  
  11.                 throw new IllegalStateException();  
  12.             } catch (IllegalStateException e) {  
  13.                 log.info(sm.getString("webappClassLoader.stopped", name), e);  
  14.             }  
  15.         }  
  16.   
  17.         // (0) Check our previously loaded local class cache  
  18.         clazz = findLoadedClass0(name);  
  19.         if (clazz != null) {  
  20.             if (log.isDebugEnabled())  
  21.                 log.debug("  Returning class from cache");  
  22.             if (resolve)  
  23.                 resolveClass(clazz);  
  24.             return (clazz);  
  25.         }  
  26.   
  27.         // (0.1) Check our previously loaded class cache  
  28.         clazz = findLoadedClass(name);  
  29.         if (clazz != null) {  
  30.             if (log.isDebugEnabled())  
  31.                 log.debug("  Returning class from cache");  
  32.             if (resolve)  
  33.                 resolveClass(clazz);  
  34.             return (clazz);  
  35.         }  
  36.   
  37.         // (0.2) Try loading the class with the system class loader, to prevent  
  38.         //       the webapp from overriding J2SE classes  
  39.         try {  
  40.             clazz = system.loadClass(name);  
  41.             if (clazz != null) {  
  42.                 if (resolve)  
  43.                     resolveClass(clazz);  
  44.                 return (clazz);  
  45.             }  
  46.         } catch (ClassNotFoundException e) {  
  47.             // Ignore  
  48.         }  
  49.   
  50.         // (0.5) Permission to access this class when using a SecurityManager  
  51.         if (securityManager != null) {  
  52.             int i = name.lastIndexOf('.');  
  53.             if (i >= 0) {  
  54.                 try {  
  55.                     securityManager.checkPackageAccess(name.substring(0,i));  
  56.                 } catch (SecurityException se) {  
  57.                     String error = "Security Violation, attempt to use " +  
  58.                         "Restricted Class: " + name;  
  59.                     log.info(error, se);  
  60.                     throw new ClassNotFoundException(error, se);  
  61.                 }  
  62.             }  
  63.         }  
  64.   
  65.         boolean delegateLoad = delegate || filter(name);  
  66.   
  67.         // (1) Delegate to our parent if requested  
  68.         if (delegateLoad) {  
  69.             if (log.isDebugEnabled())  
  70.                 log.debug("  Delegating to parent classloader1 " + parent);  
  71.             ClassLoader loader = parent;  
  72.             if (loader == null)  
  73.                 loader = system;  
  74.             try {  
  75.                 clazz = loader.loadClass(name);  
  76.                 if (clazz != null) {  
  77.                     if (log.isDebugEnabled())  
  78.                         log.debug("  Loading class from parent");  
  79.                     if (resolve)  
  80.                         resolveClass(clazz);  
  81.                     return (clazz);  
  82.                 }  
  83.             } catch (ClassNotFoundException e) {  
  84.                 ;  
  85.             }  
  86.         }  
  87.   
  88.         // (2) Search local repositories  
  89.         if (log.isDebugEnabled())  
  90.             log.debug("  Searching local repositories");  
  91.         try {  
  92.             clazz = findClass(name);  
  93.             if (clazz != null) {  
  94.                 if (log.isDebugEnabled())  
  95.                     log.debug("  Loading class from local repository");  
  96.                 if (resolve)  
  97.                     resolveClass(clazz);  
  98.                 return (clazz);  
  99.             }  
  100.         } catch (ClassNotFoundException e) {  
  101.             ;  
  102.         }  
  103.   
  104.         // (3) Delegate to parent unconditionally  
  105.         if (!delegateLoad) {  
  106.             if (log.isDebugEnabled())  
  107.                 log.debug("  Delegating to parent classloader at end: " + parent);  
  108.             ClassLoader loader = parent;  
  109.             if (loader == null)  
  110.                 loader = system;  
  111.             try {  
  112.                 clazz = loader.loadClass(name);  
  113.                 if (clazz != null) {  
  114.                     if (log.isDebugEnabled())  
  115.                         log.debug("  Loading class from parent");  
  116.                     if (resolve)  
  117.                         resolveClass(clazz);  
  118.                     return (clazz);  
  119.                 }  
  120.             } catch (ClassNotFoundException e) {  
  121.                 ;  
  122.             }  
  123.         }  
  124.   
  125.         throw new ClassNotFoundException(name);  
  126.     }  
 
 
Tomcat的过滤器主要由Filter、FilterChain组成,FilterChain包含一个Filter数组.当Wrapper执行FilterChain的doFilter(request,response)方法时,FilterChain首先调用第一个Filter的doFilter(request,response,filterchain)方法,当第一个filter做完过滤操作后,它又会调用filterchain的doFilter方法,此时filterchain的当前filter已变为第二个filter,第二个filter又执行dofilter方法,依此类推,直至所有过滤器都执行完毕 

1.接口 
Java代码 
  1. public interface Filter {  
  2.         .....         
  3.         //执行过滤  
  4.         public void doFilter ( ServletRequest request, ServletResponse response, FilterChain chain ) throws IOException, ServletException;  
  5.   
  6. }  
  7.   
  8. public interface FilterChain {  
  9.     public void doFilter ( ServletRequest request, ServletResponse response ) throws IOException, ServletException;  
  10. }  


2.实现例子 
Java代码 
  1. class ApplicationFilterChain implements FilterChain {  
  2.      
  3.    //pos为当前filter的所在位置,n为filters数组的长度  
  4.    if (pos < n) {  
  5.             //pos++执行后,把filterchain的当前filter指向下一个  
  6.             ApplicationFilterConfig filterConfig = filters[pos++];  
  7.             Filter filter = null;  
  8.             try {  
  9.                 filter = filterConfig.getFilter();  
  10.   
  11.                 //filter执行过滤操作  
  12.                 filter.doFilter(request, response, this);  
  13.             }  
  14.             ...  
  15.    }  
  16. }  
  17.   
  18.   
  19. class SampleFilter implements Filter {  
  20.       ........  
  21.       public void doFilter(ServletRequest request, ServletResponse response,FilterChain chain)  
  22.         throws IOException, ServletException {  
  23.            
  24.          //do something   
  25.          .....  
  26.          //request, response传递给下一个过滤器进行过滤  
  27.          chain.doFilter(request, response);  
  28.     }  
  29.         
  30. }  


过滤器可以在web.xml中进行配置
 

Tomcat源码分析(阀门)

关键字: tomcat源码分析
1.Tomcat组件及关系 

Server 
   --Service 
        --Connector 
        --Engine 
            --Host 
                 --Context 
                     --Wrapper(Servlet) 

Server代表Tomcat应用服务器,它可以包含多个Service服务;一个Service服务包含多个Connector和一个Engine;一个Engine可以包含多个虚拟主机Host;一个Host可以包含多个Web应用Context,而每个Web下有可以包含多个Wrapper(Servlet的包装器) 
组件及其关系可以参考Tomcat的Server.xml及Web.xml文件 


2.当一个请求到达时,Connector会把它包装成Request对象,同时生成Response对象;然后Connector会调用Engine的invoke方法,它又会调用Host的invoke 方法,Host的invoke方法又会调用Context的invoke方法,最后,Context的invoke方法调用Wrapper的invoke方法,至此,责任链调用结束。 


接口及实现: 
a.Pipeline , 此接口的实现主要用于维护阀门及先后关系,实现见  org.apache.catalina.core.StandardPipleline 
Java代码 
  1. public interface Pipeline {  
  2.      
  3.    //获取最后一个阀门   
  4.    public Valve getBasic();  
  5.      
  6.    //设置最后一个阀门  
  7.    public void setBasic(Valve valve);  
  8.   
  9.    //添加阀门  
  10.    public void addValve(Valve valve);  
  11.   
  12.    public Valve[] getValves();  
  13.   
  14.    public void removeValve(Valve valve);  
  15.   
  16.    //获取第一个阀门  
  17.    public Valve getFirst();  
  18.   
  19.     


b.Valve , 阀门接口,主要用于做过滤工作 
Java代码 
  1.   public interface Valve {  
  2.   
  3.     public String getInfo();  
  4.   
  5.     //获取下一个阀门  
  6.     public Valve getNext();  
  7.   
  8.     //设置下一个阀门  
  9.     public void setNext(Valve valve);  
  10.   
  11.     public void backgroundProcess();  
  12.   
  13.     //阀门过滤  
  14.     public void invoke(Request request, Response response)  
  15.         throws IOException, ServletException;  
  16.   
  17. }  


c.下面是与责任链有关的实现代码,以Engine的标准实现StandardEngine为例 
Java代码 
  1. StandardEngine{  
  2.       
  3.     public StandardEngine() {  
  4.         super();  
  5.         //设置StandardEngineValve为Engine的最后一个阀门  
  6.         pipeline.setBasic(new StandardEngineValve());   
  7.     }  
  8.       
  9.    //添加阀门  
  10.     public synchronized void addValve(Valve valve) {  
  11.         pipeline.addValve(valve);  
  12.     }  
  13.   
  14.     //此方法被Connector调用  
  15.     public void invoke(Request request, Response response)  
  16.         throws IOException, ServletException {  
  17.         pipeline.getFirst().invoke(request, response);  
  18.     }  
  19. }  

   
d.StandardEngine简单阀门的实现 
Java代码 
  1. SimpleValve implements Valve{  
  2.    ....  
  3.    //阀门过滤方法  
  4.     public void invoke(Request request, Response response)  
  5.         throws IOException, ServletException{  
  6.        //do something  
  7.        //调用下一个阀门的invoke方法  
  8.        getNext().invoke(Request request, Response response);  
  9.        //do something  
  10.    }  
  11. }  


e.StandardEngine最后一个阀门(StandardEngineValve)的实现 
Java代码 
  1. StandardEngineValve extends ValveBase{  
  2.    ...  
  3.    public void invoke(Request request, Response response)  
  4.         throws IOException, ServletException{  
  5.         Host host = request.getHost();  
  6.           
  7.         //至此,StandardEngine中的阀门都已处理完毕,下面把request、  
  8.          //response对象交给host处理  
  9.         host.getPipeline().getFirst().invoke(request, response);  
  10. }  


c,d,e代码即为StandardEngine责任链调用的主要代码,Host、Context、Wrapper的责任链调用相关代码与其类似,阀门可以在Server.xml及Web.xml中配置 

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多