首页 > 代码库 > StrutsPrepareAndExecuteFilter
StrutsPrepareAndExecuteFilter
StrutsPrepareAndExecuteFilter
原文转载自:http://www.iteye.com/topic/829843
一、概述
Struts2的核心是一个Filter,Action可以脱离web容器,那么是什么让http请求和action关联在一起的,下面我们深入源码来分析下Struts2是如何工作的。
鉴于常规情况官方推荐使用StrutsPrepareAndExecuteFilter替代FilterDispatcher,我们此文 将剖析StrutsPrepareAndExecuteFilter,其在工程中作为一个Filter配置在web.xml中,配置如下:
- < filter > < filter-name > </ filter-name > < filter-class ></ filter-class > </ filter > < filter-mapping > < filter-name > </ filter-name > < url-pattern > </ url-pattern > </ filter-mapping >
- <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方法初始化时做哪些工作:
- public void throws new try //封装filterConfig,其中有个主要方法getInitParameterNames将参数名字以String格式存储在List中 new // 初始化struts内部日志 //<strong>创建dispatcher ,并初始化,这部分下面我们重点分析,初始化时加载那些资源</strong> //初始化类属性:prepare 、execute newnewthis //回调空的postInit方法 finally }
- publicvoidthrowsnewtry//封装filterConfig,其中有个主要方法getInitParameterNames将参数名字以String格式存储在List中new// 初始化struts内部日志//<strong>创建dispatcher ,并初始化,这部分下面我们重点分析,初始化时加载那些资源</strong>//初始化类属性:prepare 、execute newnewthis//回调空的postInit方法finally }
首先看下FilterHostConfig ,源码如下:
- public class implements private *构造函数
- */ public this * 根据init-param配置的param-name获取param-value的值
- */ public return * 返回初始化参数名的List
- */ public return public return }
- publicclassimplementsprivate *构造函数
- */publicthis * 根据init-param配置的param-name获取param-value的值
- */publicreturn * 返回初始化参数名的List
- */publicreturnpublicreturn}
只有短短的几行代码,getInitParameterNames是这个类的核心,将Filter初始化参数名称有枚举类型转为Iterator。此类的主要作为是对filterConfig 封装。
重点来了,创建并初始化Dispatcher
- public return }
- publicreturn }
创建Dispatcher,会读取 filterConfig 中的配置信息,将配置信息解析出来,封装成为一个Map,然后根绝servlet上下文和参数Map构造Dispatcher :
- private new for return new }
- privatenewforreturnnew }
Dispatcher初始化,加载struts2的相关配置文件,将按照顺序逐一加载:default.properties,struts-default.xml,struts-plugin.xml,struts.xml,……
- /**
- *初始化过程中依次加载如下配置文件
- */ public void if null newtry
- this if for this catch if throw new }
- /**
- *初始化过程中依次加载如下配置文件
- */publicvoidifnullnewtry
- thisifforthiscatchifthrownew }
初始化default.properties,具体的初始化操作在DefaultPropertiesProvider类中
- private void new }
- privatevoidnew }
下面我们看下DefaultPropertiesProvider类源码:
- public void throws null try new );
- catch throw new }
- publicvoidthrowsnulltrynew);
- catchthrownew }
其他的我们再次省略,大家可以浏览下各个初始化操作都加载了那些文件
3、doFilter方法
doFilter是过滤器的执行方法,它拦截提交的HttpServletRequest请求,HttpServletResponse响应,作为strtus2的核心拦截器,在doFilter里面到底做了哪些工作,我们将逐行解读其源码,源码如下:
- public void throws
- try
- if null else true if null boolean if else finally }
- publicvoidthrows
- try
- ifnullelsetrueifnullbooleanifelsefinally }
setEncodingAndLocale调用了dispatcher方法的prepare方法:
- /**
- * Sets the request encoding and locale on the response
- */ public void }
- /**
- * Sets the request encoding and locale on the response
- */publicvoid }
下面我们看下prepare方法,这个方法很简单只是设置了encoding 、locale ,做的只是一些辅助的工作:
- public void null if null null if null if null try catch if null if ); }
- publicvoidnullifnullnullifnullifnulltrycatchifnullif); }
Action上下文创建(重点)
ActionContext是一个容器,这个容易主要存储request、session、application、parameters等相关信 息.ActionContext是一个线程的本地变量,这意味着不同的action之间不会共享ActionContext,所以也不用考虑线程安全问 题。其实质是一个Map,key是标示request、session、……的字符串,值是其对应的对象:
- static new Map<String, Object> context;
- staticnewMap<String, Object> context;
下面我们看下如何创建action上下文的,代码如下:
- /**
- *创建Action上下文,初始化thread local
- */ public;
- if null ;
- if null
- new new else classnull
- new
- return }
- /**
- *创建Action上下文,初始化thread local
- */public;
- ifnull;
- ifnull
- newnewelseclassnull
- new
- return}
上面代码中dispatcher.createContextMap,如何封装相关参数:
- public
- new
- new
- new
- new
- if null return }
- public
- new
- new
- new
- new
- ifnullreturn}
我们简单看下RequestMap,其他的省略。RequestMap类实现了抽象Map,故其本身是一个Map,主要方法实现:
- //map的get实现 public return //map的put实现 public null return }
- //map的get实现publicreturn//map的put实现publicnullreturn}
下面是源码展示了如何执行Action控制器:
- public voidthrows public voidthrows
- boolean null if if null if null try
- classtrue false
- if null else
- if catch
- if if null + request.getQueryString();
- else catch finally }
- publicvoidthrowspublicvoidthrows
- booleannullififnullifnulltry
- classtruefalse
- ifnullelse
- ifcatch
- ififnull + request.getQueryString();
- elsecatchfinally }
文中对如何解析Struts.xml,如何将URL与action映射匹配为分析,有需要的我后续补全,因为 StrutsXmlConfigurationProvider继承XmlConfigurationProvider,并在register方法回调父 类的register,有兴趣的可以深入阅读下下XmlConfigurationProvider源码:
- public void throws if null classclass new public throws return
- super }
- publicvoidthrowsifnullclassclassnewpublicthrowsreturn
- super }
struts2-core-2.2.1.jar包中struts-2.1.7.dtd对于Action的定义如下:
- <!ELEMENT action (param|result|interceptor-ref|exception-mapping)* > >
- <!ELEMENT action (param|result|interceptor-ref|exception-mapping)*>>
从上述DTD中可见Action元素可以含有name 、class 、method 、converter 属性。
XmlConfigurationProvider解析struts.xml配置的Action元素:
- protected void throws );
- );
- );
- if null
- ) ? methodName.trim() : null
- if
- className = packageContext.getDefaultClassRef();
- } else {
- className = ActionSupport.class.getName();
- }*/ else if if return try catch throw new newif ) : ) + name + }
- protectedvoidthrows);
- );
- );
- ifnull
- ) ? methodName.trim() : null
- if
- className = packageContext.getDefaultClassRef();
- } else {
- className = ActionSupport.class.getName();
- }*/elseififreturntrycatchthrownewnewif) : ) + name + }
工作中不涉及Struts2,本周工作有个2天的空档期,稍微看了下struts2的文档,写了个demo,从源码的角度研究了下运行原理,如有分析不当请指出,我后续逐步完善更正,大家共同提高。
一、概述
Struts2的核心是一个Filter,Action可以脱离web容器,那么是什么让http请求和action关联在一起的,下面我们深入源码来分析下Struts2是如何工作的。
鉴于常规情况官方推荐使用StrutsPrepareAndExecuteFilter替代FilterDispatcher,我们此文 将剖析StrutsPrepareAndExecuteFilter,其在工程中作为一个Filter配置在web.xml中,配置如下:
- < filter > < filter-name > </ filter-name > < filter-class ></ filter-class ></ filter > < filter-mapping > < filter-name > </ filter-name > < url-pattern > </ url-pattern > </ filter-mapping >
- <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方法初始化时做哪些工作:
- public void throws new try //封装filterConfig,其中有个主要方法getInitParameterNames将参数名字以String格式存储在List中 new // 初始化struts内部日志 //<strong>创建dispatcher ,并初始化,这部分下面我们重点分析,初始化时加载那些资源</strong> //初始化类属性:prepare 、execute newnewthis //回调空的postInit方法 finally }
- publicvoidthrowsnewtry//封装filterConfig,其中有个主要方法getInitParameterNames将参数名字以String格式存储在List中new// 初始化struts内部日志//<strong>创建dispatcher ,并初始化,这部分下面我们重点分析,初始化时加载那些资源</strong>//初始化类属性:prepare 、execute newnewthis//回调空的postInit方法finally }
首先看下FilterHostConfig ,源码如下:
- public class implements private *构造函数
- */ public this * 根据init-param配置的param-name获取param-value的值
- */ public return * 返回初始化参数名的List
- */ public return public return }
- publicclassimplementsprivate *构造函数
- */publicthis * 根据init-param配置的param-name获取param-value的值
- */publicreturn * 返回初始化参数名的List
- */publicreturnpublicreturn}
只有短短的几行代码,getInitParameterNames是这个类的核心,将Filter初始化参数名称有枚举类型转为Iterator。此类的主要作为是对filterConfig 封装。
重点来了,创建并初始化Dispatcher
- public return }
- publicreturn }
创建Dispatcher,会读取 filterConfig 中的配置信息,将配置信息解析出来,封装成为一个Map,然后根绝servlet上下文和参数Map构造Dispatcher :
- private new for return new }
- privatenewforreturnnew }
Dispatcher初始化,加载struts2的相关配置文件,将按照顺序逐一加载:default.properties,struts-default.xml,struts-plugin.xml,struts.xml,……
- /**
- *初始化过程中依次加载如下配置文件
- */ public void if null newtry
- this if for this catch if throw new }
- /**
- *初始化过程中依次加载如下配置文件
- */publicvoidifnullnewtry
- thisifforthiscatchifthrownew }
初始化default.properties,具体的初始化操作在DefaultPropertiesProvider类中
- private void new }
- privatevoidnew }
下面我们看下DefaultPropertiesProvider类源码:
- public void throws null try new );
- catch throw new }
- publicvoidthrowsnulltrynew);
- catchthrownew }
其他的我们再次省略,大家可以浏览下各个初始化操作都加载了那些文件
3、doFilter方法
doFilter是过滤器的执行方法,它拦截提交的HttpServletRequest请求,HttpServletResponse响应,作为strtus2的核心拦截器,在doFilter里面到底做了哪些工作,我们将逐行解读其源码,源码如下:
- public void throws
- try
- if null else true if null boolean if else finally }
- publicvoidthrows
- try
- ifnullelsetrueifnullbooleanifelsefinally }
setEncodingAndLocale调用了dispatcher方法的prepare方法:
- /**
- * Sets the request encoding and locale on the response
- */ public void }
- /**
- * Sets the request encoding and locale on the response
- */publicvoid }
下面我们看下prepare方法,这个方法很简单只是设置了encoding 、locale ,做的只是一些辅助的工作:
- public void null if null null if null if null try catch if null if ); }
- publicvoidnullifnullnullifnullifnulltrycatchifnullif); }
Action上下文创建(重点)
ActionContext是一个容器,这个容易主要存储request、session、application、parameters等相关信 息.ActionContext是一个线程的本地变量,这意味着不同的action之间不会共享ActionContext,所以也不用考虑线程安全问 题。其实质是一个Map,key是标示request、session、……的字符串,值是其对应的对象:
- static new Map<String, Object> context;
- staticnewMap<String, Object> context;
下面我们看下如何创建action上下文的,代码如下:
- /**
- *创建Action上下文,初始化thread local
- */ public;
- if null ;
- if null
- new new else classnull
- new
- return }
- /**
- *创建Action上下文,初始化thread local
- */public;
- ifnull;
- ifnull
- newnewelseclassnull
- new
- return}
上面代码中dispatcher.createContextMap,如何封装相关参数:
- public
- new
- new
- new
- new
- if null return }
- public
- new
- new
- new
- new
- ifnullreturn}
我们简单看下RequestMap,其他的省略。RequestMap类实现了抽象Map,故其本身是一个Map,主要方法实现:
- //map的get实现 public return //map的put实现 public null return }
- //map的get实现publicreturn//map的put实现publicnullreturn}
下面是源码展示了如何执行Action控制器:
- public voidthrows public voidthrows
- boolean null if if null if null try
- classtrue false
- if null else
- if catch
- if if null + request.getQueryString();
- else catch finally }
- publicvoidthrowspublicvoidthrows
- booleannullififnullifnulltry
- classtruefalse
- ifnullelse
- ifcatch
- ififnull + request.getQueryString();
- elsecatchfinally }
文中对如何解析Struts.xml,如何将URL与action映射匹配为分析,有需要的我后续补全,因为 StrutsXmlConfigurationProvider继承XmlConfigurationProvider,并在register方法回调父 类的register,有兴趣的可以深入阅读下下XmlConfigurationProvider源码:
- public void throws if null classclass new public throws return
- super }
- publicvoidthrowsifnullclassclassnewpublicthrowsreturn
- super }
struts2-core-2.2.1.jar包中struts-2.1.7.dtd对于Action的定义如下:
- <!ELEMENT action (param|result|interceptor-ref|exception-mapping)* > >
- <!ELEMENT action (param|result|interceptor-ref|exception-mapping)*>>
从上述DTD中可见Action元素可以含有name 、class 、method 、converter 属性。
XmlConfigurationProvider解析struts.xml配置的Action元素:
- protected void throws );
- );
- );
- if null
- ) ? methodName.trim() : null
- if
- className = packageContext.getDefaultClassRef();
- } else {
- className = ActionSupport.class.getName();
- }*/ else if if return try catch throw new newif ) : ) + name + }
- protectedvoidthrows);
- );
- );
- ifnull
- ) ? methodName.trim() : null
- if
- className = packageContext.getDefaultClassRef();
- } else {
- className = ActionSupport.class.getName();
- }*/elseififreturntrycatchthrownewnewif) : ) + name + }
StrutsPrepareAndExecuteFilter