首页 > 代码库 > StrutsPrepareAndExecuteFilter

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中,配置如下:

Xml代码  技术分享
  1. filter  filter-name </ filter-name  filter-class ></ filter-class > </ filter  filter-mapping  filter-name </ filter-name  url-pattern </ url-pattern  </ filter-mapping   
[xml] view plaincopy
 
  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  ExecuteOperationsexecute 
           
protected  PrepareOperationsprepare 
           

 

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

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

 

三、源码剖析    

 

    1、init方法

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

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

 

   首先看下FilterHostConfig ,源码如下:

 

Java代码  技术分享
  1. public class implements private      *构造函数    
  2.      */ public this      *  根据init-param配置的param-name获取param-value的值  
  3.      */ public return          *  返回初始化参数名的List  
  4.      */ public return public return }  
[java] view plaincopy
 
  1. publicclassimplementsprivate     *构造函数   
  2.      */publicthis     *  根据init-param配置的param-name获取param-value的值 
  3.      */publicreturn         *  返回初始化参数名的List 
  4.      */publicreturnpublicreturn}  

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

 

 

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

Java代码  技术分享
  1. public return    }  
[java] view plaincopy
 
  1. publicreturn   }  

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

Java代码  技术分享
  1. private new for return new     }  
[java] view plaincopy
 
  1. privatenewforreturnnew    }  

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

 

Java代码  技术分享
  1. /**  
  2. *初始化过程中依次加载如下配置文件  
  3. */ public void if null newtry   
  4.   
  5.   
  6.   
  7.   
  8.   
  9.   
  10.   
  11.   
  12.   
  13. this if for this catch if  throw new     }  
[java] view plaincopy
 
  1. /** 
  2. *初始化过程中依次加载如下配置文件 
  3. */publicvoidifnullnewtry  
  4.   
  5.   
  6.   
  7.   
  8.   
  9.   
  10.   
  11.   
  12.   
  13. thisifforthiscatchifthrownew    }  

 

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

  

Java代码  技术分享
  1. private void new    }  
[java] view plaincopy
 
  1. privatevoidnew   }  

    

   下面我们看下DefaultPropertiesProvider类源码:

 

Java代码  技术分享
  1. public void throws null try new );  
  2. catch throw new      }  
[java] view plaincopy
 
  1. publicvoidthrowsnulltrynew);  
  2. catchthrownew    }  

 

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

 


3、doFilter方法

 

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

 

Java代码  技术分享
  1.   public void throws   
  2. try   
  3.   
  4. if null else true if null boolean if else finally  }  
[java] view plaincopy
 
  1.  publicvoidthrows  
  2. try  
  3.   
  4. ifnullelsetrueifnullbooleanifelsefinally }  

 

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

 

Java代码  技术分享
  1. /**  
  2.      * Sets the request encoding and locale on the response  
  3.      */ public void    }  
[java] view plaincopy
 
  1. /** 
  2.      * Sets the request encoding and locale on the response 
  3.      */publicvoid    }  

 

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

Java代码  技术分享
  1. public void null if null null if null if null try catch   if null if );      }  
[java] view plaincopy
 
  1. publicvoidnullifnullnullifnullifnulltrycatchifnullif);     }  

 

   Action上下文创建(重点)

 

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

Java代码  技术分享
  1. static new Map<String, Object> context;  
[java] view plaincopy
 
  1. staticnewMap<String, Object> context;  

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

 

Java代码  技术分享
  1. /**  
  2. *创建Action上下文,初始化thread local  
  3. */ public;  
  4. if null ;  
  5.   
  6. if null   
  7. new new else classnull  
  8. new   
  9. return }  
[java] view plaincopy
 
  1. /** 
  2. *创建Action上下文,初始化thread local 
  3. */public;  
  4. ifnull;  
  5.   
  6. ifnull  
  7. newnewelseclassnull  
  8. new  
  9. return}  

 

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

 

Java代码  技术分享
  1. public  
  2. new   
  3. new   
  4. new   
  5. new   
  6. if null return }  
[java] view plaincopy
 
  1. public  
  2. new  
  3. new  
  4. new  
  5. new  
  6. ifnullreturn}  

 

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

Java代码  技术分享
  1. //map的get实现 public return //map的put实现 public null return }  
[java] view plaincopy
 
  1. //map的get实现publicreturn//map的put实现publicnullreturn}  

 

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

 

Java代码  技术分享
  1. public voidthrows public voidthrows   
  2.   
  3. boolean null if if null if null  try   
  4.   
  5.   
  6.   
  7. classtrue false   
  8.   
  9. if null else   
  10. if catch   
  11. if if null  + request.getQueryString();  
  12.  else  catch finally     }  
[java] view plaincopy
 
  1. publicvoidthrowspublicvoidthrows  
  2.   
  3. booleannullififnullifnulltry  
  4.   
  5.   
  6.   
  7. classtruefalse  
  8.   
  9. ifnullelse  
  10. ifcatch  
  11. ififnull + request.getQueryString();  
  12. elsecatchfinally    }  

 

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

 

Java代码  技术分享
  1. public void throws if null classclass new public throws return   
  2. super    }  
[java] view plaincopy
 
  1. publicvoidthrowsifnullclassclassnewpublicthrowsreturn  
  2. super   }  

 

 

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

Xml代码  技术分享
  1. <!ELEMENT action (param|result|interceptor-ref|exception-mapping)*   
[xml] view plaincopy
 
  1. <!ELEMENT action (param|result|interceptor-ref|exception-mapping)*>>  

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

 

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

Java代码  技术分享
  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  newif ) :  ) + name +    }  
[java] view plaincopy
 
  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.          }*/elseififreturntrycatchthrownewnewif) : ) + 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中,配置如下:

Xml代码  技术分享
  1. filter filter-name </ filter-name filter-class ></ filter-class ></ filter filter-mapping filter-name </ filter-name url-pattern </ url-pattern </ filter-mapping   
[xml] view plaincopy
 
  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  ExecuteOperationsexecute 
           
protected  PrepareOperationsprepare 
           

 

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

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

 

三、源码剖析    

 

    1、init方法

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

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

 

   首先看下FilterHostConfig ,源码如下:

 

Java代码  技术分享
  1. public class implements private      *构造函数    
  2.      */ public this      *  根据init-param配置的param-name获取param-value的值  
  3.      */ public return          *  返回初始化参数名的List  
  4.      */ public return public return }  
[java] view plaincopy
 
  1. publicclassimplementsprivate     *构造函数   
  2.      */publicthis     *  根据init-param配置的param-name获取param-value的值 
  3.      */publicreturn         *  返回初始化参数名的List 
  4.      */publicreturnpublicreturn}  

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

 

 

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

Java代码  技术分享
  1. public return    }  
[java] view plaincopy
 
  1. publicreturn   }  

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

Java代码  技术分享
  1. private new for return new     }  
[java] view plaincopy
 
  1. privatenewforreturnnew    }  

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

 

Java代码  技术分享
  1. /**  
  2. *初始化过程中依次加载如下配置文件  
  3. */ public void if null newtry   
  4.   
  5.   
  6.   
  7.   
  8.   
  9.   
  10.   
  11.   
  12.   
  13. this if for this catch if  throw new     }  
[java] view plaincopy
 
  1. /** 
  2. *初始化过程中依次加载如下配置文件 
  3. */publicvoidifnullnewtry  
  4.   
  5.   
  6.   
  7.   
  8.   
  9.   
  10.   
  11.   
  12.   
  13. thisifforthiscatchifthrownew    }  

 

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

  

Java代码  技术分享
  1. private void new    }  
[java] view plaincopy
 
  1. privatevoidnew   }  

    

   下面我们看下DefaultPropertiesProvider类源码:

 

Java代码  技术分享
  1. public void throws null try new );  
  2. catch throw new      }  
[java] view plaincopy
 
  1. publicvoidthrowsnulltrynew);  
  2. catchthrownew    }  

 

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

 


3、doFilter方法

 

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

 

Java代码  技术分享
  1.   public void throws   
  2. try   
  3.   
  4. if null else true if null boolean if else finally  }  
[java] view plaincopy
 
  1.  publicvoidthrows  
  2. try  
  3.   
  4. ifnullelsetrueifnullbooleanifelsefinally }  

 

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

 

Java代码  技术分享
  1. /**  
  2.      * Sets the request encoding and locale on the response  
  3.      */ public void    }  
[java] view plaincopy
 
  1. /** 
  2.      * Sets the request encoding and locale on the response 
  3.      */publicvoid    }  

 

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

Java代码  技术分享
  1. public void null if null null if null if null try catch   if null if );      }  
[java] view plaincopy
 
  1. publicvoidnullifnullnullifnullifnulltrycatchifnullif);     }  

 

   Action上下文创建(重点)

 

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

Java代码  技术分享
  1. static new Map<String, Object> context;  
[java] view plaincopy
 
  1. staticnewMap<String, Object> context;  

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

 

Java代码  技术分享
  1. /**  
  2. *创建Action上下文,初始化thread local  
  3. */ public;  
  4. if null ;  
  5.   
  6. if null   
  7. new new else classnull  
  8. new   
  9. return }  
[java] view plaincopy
 
  1. /** 
  2. *创建Action上下文,初始化thread local 
  3. */public;  
  4. ifnull;  
  5.   
  6. ifnull  
  7. newnewelseclassnull  
  8. new  
  9. return}  

 

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

 

Java代码  技术分享
  1. public  
  2. new   
  3. new   
  4. new   
  5. new   
  6. if null return }  
[java] view plaincopy
 
  1. public  
  2. new  
  3. new  
  4. new  
  5. new  
  6. ifnullreturn}  

 

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

Java代码  技术分享
  1. //map的get实现 public return //map的put实现 public null return }  
[java] view plaincopy
 
  1. //map的get实现publicreturn//map的put实现publicnullreturn}  

 

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

 

Java代码  技术分享
  1. public voidthrows public voidthrows   
  2.   
  3. boolean null if if null if null  try   
  4.   
  5.   
  6.   
  7. classtrue false   
  8.   
  9. if null else   
  10. if catch   
  11. if if null  + request.getQueryString();  
  12.  else  catch finally     }  
[java] view plaincopy
 
  1. publicvoidthrowspublicvoidthrows  
  2.   
  3. booleannullififnullifnulltry  
  4.   
  5.   
  6.   
  7. classtruefalse  
  8.   
  9. ifnullelse  
  10. ifcatch  
  11. ififnull + request.getQueryString();  
  12. elsecatchfinally    }  

 

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

 

Java代码  技术分享
  1. public void throws if null classclass new public throws return   
  2. super    }  
[java] view plaincopy
 
  1. publicvoidthrowsifnullclassclassnewpublicthrowsreturn  
  2. super   }  

 

 

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

Xml代码  技术分享
  1. <!ELEMENT action (param|result|interceptor-ref|exception-mapping)*   
[xml] view plaincopy
 
  1. <!ELEMENT action (param|result|interceptor-ref|exception-mapping)*>>  

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

 

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

Java代码  技术分享
  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  newif ) :  ) + name +    }  
[java] view plaincopy
 
  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.          }*/elseififreturntrycatchthrownewnewif) : ) + name +  }  

 

StrutsPrepareAndExecuteFilter