首页 > 代码库 > StrutsPrepareAndExecuteFilter

StrutsPrepareAndExecuteFilter

原文转载自:http://www.iteye.com/topic/829843 

一、概述

     Struts2的核心是一个Filter,Action可以脱离web容器,那么是什么让http请求和action关联在一起的,下面我们深入源码来分析下Struts2是如何工作的。

FilterDispatcher API 写道
Deprecated. Since Struts 2.1.3, use StrutsPrepareAndExecuteFilter instead or StrutsPrepareFilter and StrutsExecuteFilter if needing using the ActionContextCleanUp filter in addition to this one

 

     鉴于常规情况官方推荐使用StrutsPrepareAndExecuteFilter替代FilterDispatcher,我们此文 将剖析StrutsPrepareAndExecuteFilter,其在工程中作为一个Filter配置在web.xml中,配置如下:

  1. filter >  < filter-name > </ filter-name >  < filter-class ></ filter-class ></ filter >  < filter-mapping >  < filter-name > </ filter-name >  < url-pattern > </ url-pattern >  </ filter-mapping >   
  1. <filter> <filter-name></filter-name> <filter-class></filter-class> </filter> <filter-mapping> <filter-name></filter-name> <url-pattern></url-pattern> </filter-mapping>  

 

二、源码属性方法简介

    下面我们研究下StrutsPrepareAndExecuteFilter源码,类的主要信息如下:

 

属性摘要
protected  List<Pattern > excludedPatterns 
           
protected  ExecuteOperations execute 
           
protected  PrepareOperations prepare 
           

 

    StrutsPrepareAndExecuteFilter与普通的Filter并无区别,方法除继承自Filter外,仅有一个回调方法,第三部分我 们将按照Filter方法调用顺序,由init—>doFilter—>destroy顺序地分析源码。

方法摘要
 void destroy () 
           继承自Filter,用于资源释放
 void doFilter (ServletRequest  req, ServletResponse  res, FilterChain  chain)  
           继承自Filter,执行方法
 void init (FilterConfig  filterConfig)  
           继承自Filter,初始化参数
protected  void postInit (Dispatcher  dispatcher, FilterConfig  filterConfig) 
          Callback for post initialization(一个空的方法,用于方法回调初始化)

 

三、源码剖析    

 

    1、init方法

         init是Filter第一个运行的方法,我们看下struts2的核心Filter在调用init方法初始化时做哪些工作:

  1.   public void throws  new  try  //封装filterConfig,其中有个主要方法getInitParameterNames将参数名字以String格式存储在List中  new  // 初始化struts内部日志  //<strong>创建dispatcher ,并初始化,这部分下面我们重点分析,初始化时加载那些资源</strong>  //初始化类属性:prepare 、execute   new new this  //回调空的postInit方法  finally   }  
  1.  publicvoidthrows new try //封装filterConfig,其中有个主要方法getInitParameterNames将参数名字以String格式存储在List中 new // 初始化struts内部日志 //<strong>创建dispatcher ,并初始化,这部分下面我们重点分析,初始化时加载那些资源</strong> //初始化类属性:prepare 、execute  newnew this //回调空的postInit方法 finally  }  

 

   首先看下FilterHostConfig ,源码如下:

 

  1. public class implements  private       *构造函数    
  2.      */  public  this       *  根据init-param配置的param-name获取param-value的值  
  3.      */  public  return           *  返回初始化参数名的List  
  4.      */  public  return  public  return  }  
  1. publicclassimplements private      *构造函数   
  2.      */ public this      *  根据init-param配置的param-name获取param-value的值 
  3.      */ public return          *  返回初始化参数名的List 
  4.      */ public return public return }  

   只有短短的几行代码,getInitParameterNames是这个类的核心,将Filter初始化参数名称有枚举类型转为Iterator。此类的主要作为是对filterConfig 封装。

 

 

    重点来了,创建并初始化Dispatcher      

  1. public  return     }  
  1. public return    }  

     创建Dispatcher,会读取 filterConfig 中的配置信息,将配置信息解析出来,封装成为一个Map,然后根绝servlet上下文和参数Map构造Dispatcher :

  1. private  new  for  return new      }  
  1. private new for returnnew     }  

  Dispatcher初始化,加载struts2的相关配置文件,将按照顺序逐一加载:default.properties,struts-default.xml,struts-plugin.xml,struts.xml,……

 

  1. /**  
  2. *初始化过程中依次加载如下配置文件  
  3. */  public void  if null  new try    
  4.   
  5.   
  6.   
  7.   
  8.   
  9.   
  10.   
  11.   
  12.   
  13. this  if  for  this  catch  if    throw new      }  
  1. /** 
  2. *初始化过程中依次加载如下配置文件 
  3. */ publicvoid ifnull new try   
  4.   
  5.   
  6.   
  7.   
  8.   
  9.   
  10.   
  11.   
  12.   
  13. this if for this catch if thrownew     }  

 

   初始化default.properties,具体的初始化操作在DefaultPropertiesProvider类中

  

  1. private void  new     }  
  1. privatevoid new    }  

    

   下面我们看下DefaultPropertiesProvider类源码:

 

  1. public void  throws  null  try  new );  
  2. catch  throw new       }  
  1. publicvoid throws null try new);  
  2. catch thrownew     }  

 

   其他的我们再次省略,大家可以浏览下各个初始化操作都加载了那些文件

 


3、doFilter方法

 

     doFilter是过滤器的执行方法,它拦截提交的HttpServletRequest请求,HttpServletResponse响应,作为strtus2的核心拦截器,在doFilter里面到底做了哪些工作,我们将逐行解读其源码,源码如下:

 

  1.   public void throws    
  2. try    
  3.   
  4. if null  else  true  if null  boolean  if  else  finally   }  
  1.  publicvoidthrows   
  2. try   
  3.   
  4. ifnull else true ifnull boolean if else finally  }  

 

    setEncodingAndLocale调用了dispatcher方法的prepare方法:

 

  1. /**  
  2.      * Sets the request encoding and locale on the response  
  3.      */  public void     }  
  1. /** 
  2.      * Sets the request encoding and locale on the response 
  3.      */ publicvoid     }  

 

   下面我们看下prepare方法,这个方法很简单只是设置了encoding 、locale ,做的只是一些辅助的工作:

  1. public void  null  if null  null  if null  if null  try  catch     if null  if  );      }  
  1. publicvoid null ifnull null ifnull ifnull try catch ifnull if );      }  

 

   Action上下文创建(重点)

 

       ActionContext是一个容器,这个容易主要存储request、session、application、parameters等相关信 息.ActionContext是一个线程的本地变量,这意味着不同的action之间不会共享ActionContext,所以也不用考虑线程安全问 题。其实质是一个Map,key是标示request、session、……的字符串,值是其对应的对象:

  1. static new  Map<String, Object> context;  
  1. staticnew Map<String, Object> context;  

 
   下面我们看下如何创建action上下文的,代码如下:

 

  1. /**  
  2. *创建Action上下文,初始化thread local  
  3. */  public ;  
  4. if null  ;  
  5.   
  6. if null    
  7. new new  else  class null   
  8. new    
  9. return  }  
  1. /** 
  2. *创建Action上下文,初始化thread local 
  3. */ public ;  
  4. ifnull ;  
  5.   
  6. ifnull   
  7. newnew else class null   
  8. new   
  9. return }  

 

    上面代码中dispatcher.createContextMap,如何封装相关参数:

 

  1. public   
  2. new    
  3. new    
  4. new    
  5. new    
  6. if null  return  }  
  1. public   
  2. new   
  3. new   
  4. new   
  5. new   
  6. ifnull return }  

 

 我们简单看下RequestMap,其他的省略。RequestMap类实现了抽象Map,故其本身是一个Map,主要方法实现:

  1. //map的get实现  public  return  //map的put实现  public  null  return  }  
  1. //map的get实现 public return //map的put实现 public null return }  

 

   下面是源码展示了如何执行Action控制器:

 

  1. public voidthrows  public void throws    
  2.   
  3. boolean null  if  if null  if null    try    
  4.   
  5.   
  6.   
  7. class true false    
  8.   
  9. if null  else    
  10. if  catch    
  11. if  if null   + request.getQueryString();  
  12.   else    catch  finally      }  
  1. publicvoidthrows publicvoid throws   
  2.   
  3. booleannull if ifnull ifnull try   
  4.   
  5.   
  6.   
  7. class truefalse   
  8.   
  9. ifnull else   
  10. if catch   
  11. if ifnull  + request.getQueryString();  
  12. else catch finally     }  

 

   文中对如何解析Struts.xml,如何将URL与action映射匹配为分析,有需要的我后续补全,因为 StrutsXmlConfigurationProvider继承XmlConfigurationProvider,并在register方法回调父 类的register,有兴趣的可以深入阅读下下XmlConfigurationProvider源码:

 

  1. public void throws  if null class class new  public throws  return    
  2. super     }  
  1. publicvoidthrows ifnullclass classnew publicthrows return   
  2. super    }  

 

 

     struts2-core-2.2.1.jar包中struts-2.1.7.dtd对于Action的定义如下:

  1. <!ELEMENT action (param|result|interceptor-ref|exception-mapping)* >  >   
  1. <!ELEMENT action (param|result|interceptor-ref|exception-mapping)*> >  

    从上述DTD中可见Action元素可以含有name 、class 、method 、converter 属性。

 

   XmlConfigurationProvider解析struts.xml配置的Action元素:

  1. protected void throws  );  
  2. );  
  3. );  
  4. if null      
  5. ) ? methodName.trim() :  null    
  6.   
  7. if    
  8.              className = packageContext.getDefaultClassRef();  
  9.          } else {  
  10.              className = ActionSupport.class.getName();  
  11.          }*/  else  if  if  return  try  catch  throw new   new if  ) :  ) + name +    }  
  1. protectedvoidthrows );  
  2. );  
  3. );  
  4. ifnull   
  5. ) ? methodName.trim() : null   
  6.   
  7. if   
  8.              className = packageContext.getDefaultClassRef(); 
  9.          } else { 
  10.              className = ActionSupport.class.getName(); 
  11.          }*/ else if if return try catch thrownew new if ) : ) + name +   }  

 

 

     工作中不涉及Struts2,本周工作有个2天的空档期,稍微看了下struts2的文档,写了个demo,从源码的角度研究了下运行原理,如有分析不当请指出,我后续逐步完善更正,大家共同提高。

 一、概述

     Struts2的核心是一个Filter,Action可以脱离web容器,那么是什么让http请求和action关联在一起的,下面我们深入源码来分析下Struts2是如何工作的。

FilterDispatcher API 写道
Deprecated. Since Struts 2.1.3, use StrutsPrepareAndExecuteFilter instead or StrutsPrepareFilter and StrutsExecuteFilter if needing using the ActionContextCleanUp filter in addition to this one

 

     鉴于常规情况官方推荐使用StrutsPrepareAndExecuteFilter替代FilterDispatcher,我们此文 将剖析StrutsPrepareAndExecuteFilter,其在工程中作为一个Filter配置在web.xml中,配置如下:

  1. filter >  < filter-name > </ filter-name >  < filter-class ></ filter-class ></ filter >  < filter-mapping >  < filter-name > </ filter-name >  < url-pattern > </ url-pattern >  </ filter-mapping >   
  1. <filter> <filter-name></filter-name> <filter-class></filter-class> </filter> <filter-mapping> <filter-name></filter-name> <url-pattern></url-pattern> </filter-mapping>  

 

二、源码属性方法简介

    下面我们研究下StrutsPrepareAndExecuteFilter源码,类的主要信息如下:

 

属性摘要
protected  List<Pattern > excludedPatterns 
           
protected  ExecuteOperations execute 
           
protected  PrepareOperations prepare 
           

 

    StrutsPrepareAndExecuteFilter与普通的Filter并无区别,方法除继承自Filter外,仅有一个回调方法,第三部分我 们将按照Filter方法调用顺序,由init—>doFilter—>destroy顺序地分析源码。

方法摘要
 void destroy () 
           继承自Filter,用于资源释放
 void doFilter (ServletRequest  req, ServletResponse  res, FilterChain  chain)  
           继承自Filter,执行方法
 void init (FilterConfig  filterConfig)  
           继承自Filter,初始化参数
protected  void postInit (Dispatcher  dispatcher, FilterConfig  filterConfig) 
          Callback for post initialization(一个空的方法,用于方法回调初始化)

 

三、源码剖析    

 

    1、init方法

         init是Filter第一个运行的方法,我们看下struts2的核心Filter在调用init方法初始化时做哪些工作:

  1.   public void throws  new  try  //封装filterConfig,其中有个主要方法getInitParameterNames将参数名字以String格式存储在List中  new  // 初始化struts内部日志  //<strong>创建dispatcher ,并初始化,这部分下面我们重点分析,初始化时加载那些资源</strong>  //初始化类属性:prepare 、execute   new new this  //回调空的postInit方法  finally   }  
  1.  publicvoidthrows new try //封装filterConfig,其中有个主要方法getInitParameterNames将参数名字以String格式存储在List中 new // 初始化struts内部日志 //<strong>创建dispatcher ,并初始化,这部分下面我们重点分析,初始化时加载那些资源</strong> //初始化类属性:prepare 、execute  newnew this //回调空的postInit方法 finally  }  

 

   首先看下FilterHostConfig ,源码如下:

 

  1. public class implements  private       *构造函数    
  2.      */  public  this       *  根据init-param配置的param-name获取param-value的值  
  3.      */  public  return           *  返回初始化参数名的List  
  4.      */  public  return  public  return  }  
  1. publicclassimplements private      *构造函数   
  2.      */ public this      *  根据init-param配置的param-name获取param-value的值 
  3.      */ public return          *  返回初始化参数名的List 
  4.      */ public return public return }  

   只有短短的几行代码,getInitParameterNames是这个类的核心,将Filter初始化参数名称有枚举类型转为Iterator。此类的主要作为是对filterConfig 封装。

 

 

    重点来了,创建并初始化Dispatcher      

  1. public  return     }  
  1. public return    }  

     创建Dispatcher,会读取 filterConfig 中的配置信息,将配置信息解析出来,封装成为一个Map,然后根绝servlet上下文和参数Map构造Dispatcher :

  1. private  new  for  return new      }  
  1. private new for returnnew     }  

  Dispatcher初始化,加载struts2的相关配置文件,将按照顺序逐一加载:default.properties,struts-default.xml,struts-plugin.xml,struts.xml,……

 

  1. /**  
  2. *初始化过程中依次加载如下配置文件  
  3. */  public void  if null  new try    
  4.   
  5.   
  6.   
  7.   
  8.   
  9.   
  10.   
  11.   
  12.   
  13. this  if  for  this  catch  if    throw new      }  
  1. /** 
  2. *初始化过程中依次加载如下配置文件 
  3. */ publicvoid ifnull new try   
  4.   
  5.   
  6.   
  7.   
  8.   
  9.   
  10.   
  11.   
  12.   
  13. this if for this catch if thrownew     }  

 

   初始化default.properties,具体的初始化操作在DefaultPropertiesProvider类中

  

  1. private void  new     }  
  1. privatevoid new    }  

    

   下面我们看下DefaultPropertiesProvider类源码:

 

  1. public void  throws  null  try  new );  
  2. catch  throw new       }  
  1. publicvoid throws null try new);  
  2. catch thrownew     }  

 

   其他的我们再次省略,大家可以浏览下各个初始化操作都加载了那些文件

 


3、doFilter方法

 

     doFilter是过滤器的执行方法,它拦截提交的HttpServletRequest请求,HttpServletResponse响应,作为strtus2的核心拦截器,在doFilter里面到底做了哪些工作,我们将逐行解读其源码,源码如下:

 

  1.   public void throws    
  2. try    
  3.   
  4. if null  else  true  if null  boolean  if  else  finally   }  
  1.  publicvoidthrows   
  2. try   
  3.   
  4. ifnull else true ifnull boolean if else finally  }  

 

    setEncodingAndLocale调用了dispatcher方法的prepare方法:

 

  1. /**  
  2.      * Sets the request encoding and locale on the response  
  3.      */  public void     }  
  1. /** 
  2.      * Sets the request encoding and locale on the response 
  3.      */ publicvoid     }  

 

   下面我们看下prepare方法,这个方法很简单只是设置了encoding 、locale ,做的只是一些辅助的工作:

  1. public void  null  if null  null  if null  if null  try  catch     if null  if  );      }  
  1. publicvoid null ifnull null ifnull ifnull try catch ifnull if );      }  

 

   Action上下文创建(重点)

 

       ActionContext是一个容器,这个容易主要存储request、session、application、parameters等相关信 息.ActionContext是一个线程的本地变量,这意味着不同的action之间不会共享ActionContext,所以也不用考虑线程安全问 题。其实质是一个Map,key是标示request、session、……的字符串,值是其对应的对象:

  1. static new  Map<String, Object> context;  
  1. staticnew Map<String, Object> context;  

 
   下面我们看下如何创建action上下文的,代码如下:

 

  1. /**  
  2. *创建Action上下文,初始化thread local  
  3. */  public ;  
  4. if null  ;  
  5.   
  6. if null    
  7. new new  else  class null   
  8. new    
  9. return  }  
  1. /** 
  2. *创建Action上下文,初始化thread local 
  3. */ public ;  
  4. ifnull ;  
  5.   
  6. ifnull   
  7. newnew else class null   
  8. new   
  9. return }  

 

    上面代码中dispatcher.createContextMap,如何封装相关参数:

 

  1. public   
  2. new    
  3. new    
  4. new    
  5. new    
  6. if null  return  }  
  1. public   
  2. new   
  3. new   
  4. new   
  5. new   
  6. ifnull return }  

 

 我们简单看下RequestMap,其他的省略。RequestMap类实现了抽象Map,故其本身是一个Map,主要方法实现:

  1. //map的get实现  public  return  //map的put实现  public  null  return  }  
  1. //map的get实现 public return //map的put实现 public null return }  

 

   下面是源码展示了如何执行Action控制器:

 

  1. public voidthrows  public void throws    
  2.   
  3. boolean null  if  if null  if null    try    
  4.   
  5.   
  6.   
  7. class true false    
  8.   
  9. if null  else    
  10. if  catch    
  11. if  if null   + request.getQueryString();  
  12.   else    catch  finally      }  
  1. publicvoidthrows publicvoid throws   
  2.   
  3. booleannull if ifnull ifnull try   
  4.   
  5.   
  6.   
  7. class truefalse   
  8.   
  9. ifnull else   
  10. if catch   
  11. if ifnull  + request.getQueryString();  
  12. else catch finally     }  

 

   文中对如何解析Struts.xml,如何将URL与action映射匹配为分析,有需要的我后续补全,因为 StrutsXmlConfigurationProvider继承XmlConfigurationProvider,并在register方法回调父 类的register,有兴趣的可以深入阅读下下XmlConfigurationProvider源码:

 

  1. public void throws  if null class class new  public throws  return    
  2. super     }  
  1. publicvoidthrows ifnullclass classnew publicthrows return   
  2. super    }  

 

 

     struts2-core-2.2.1.jar包中struts-2.1.7.dtd对于Action的定义如下:

  1. <!ELEMENT action (param|result|interceptor-ref|exception-mapping)* >  >   
  1. <!ELEMENT action (param|result|interceptor-ref|exception-mapping)*> >  

    从上述DTD中可见Action元素可以含有name 、class 、method 、converter 属性。

 

   XmlConfigurationProvider解析struts.xml配置的Action元素:

  1. protected void throws  );  
  2. );  
  3. );  
  4. if null      
  5. ) ? methodName.trim() :  null    
  6.   
  7. if    
  8.              className = packageContext.getDefaultClassRef();  
  9.          } else {  
  10.              className = ActionSupport.class.getName();  
  11.          }*/  else  if  if  return  try  catch  throw new   new if  ) :  ) + name +    }  
    1. protectedvoidthrows );  
    2. );  
    3. );  
    4. ifnull   
    5. ) ? methodName.trim() : null   
    6.   
    7. if   
    8.              className = packageContext.getDefaultClassRef(); 
    9.          } else { 
    10.              className = ActionSupport.class.getName(); 
    11.          }*/ else if if return try catch thrownew new if ) : ) + name +   }  

StrutsPrepareAndExecuteFilter