Struts2 源码分析-----工作原理分析

请求过程struts2架构图如下图所示:依照上图,我们可以看出一个请求在struts的处理大概有如下步骤:1、客户端初始化一个指向Servlet容器(例如Tomcat)的请求;2、这个请求经过一系列的过滤器(Filter)(这些过滤器中有一个叫做ActionContextCleanUp的可选过滤器,这个过滤器对于Struts2和其他框架的集成很有帮助,例如:SiteMeshPlugin);3、接着...

Struts2 源码分析-----工作原理分析

请求过程

struts2 架构图如下图所示:

依照上图,我们可以看出一个请求在struts的处理大概有如下步骤:

  1、客户端初始化一个指向Servlet容器(例如Tomcat)的请求;

  2、这个请求经过一系列的过滤器(Filter)(这些过滤器中有一个叫做ActionContextCleanUp的可选过滤器,这个过滤器对于Struts2和其他框架的集成很有帮助,例如:SiteMesh Plugin);

  3、接着StrutsPrepareAndExecuteFilter被调用,StrutsPrepareAndExecuteFilter询问ActionMapper来决定这个请求是否需要调用某个Action;

  4、如果ActionMapper决定需要调用某个Action,FilterDispatcher把请求的处理交给ActionProxy;

  5、ActionProxy通过Configuration Manager询问框架的配置文件,找到需要调用的Action类;

  6、ActionProxy创建一个ActionInvocation的实例。

  7、ActionInvocation实例使用命名模式来调用,在调用Action的过程前后,涉及到相关拦截器(Intercepter)的调用。

  8、一旦Action执行完毕,ActionInvocation负责根据struts.xml中的配置找到对应的返回结果。返回结果通常是(但不总是,也可能是另外的一个Action链)一个需要被表示的JSP或者FreeMarker的模版。在表示的过程中可以使用Struts2 框架中继承的标签。在这个过程中需要涉及到ActionMapper。

  9、接着按照相反次序执行拦截器链 ( 执行 Action 调用之后的部分 )。最后,响应通过滤器链返回(过滤器技术执行流程与拦截器一样,都是先执行前面部分,后执行后面部)。如果过滤器链中存在 ActionContextCleanUp,FilterDispatcher 不会清理线程局部的 ActionContext。如果不存在 ActionContextCleanUp 过滤器,FilterDispatcher 会清除所有线程局部变量。

strut2源码分析

  首先我们使用struts2框架都会在web.xml中注册和映射struts2,配置内容如下:

<filter>  <filter-name>struts2</filter-name><filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class> </filter>  <filter-mapping>  <filter-name>struts2</filter-name><url-pattern>/*</url-pattern> </filter-mapping>

注:在早期的struts2中,都是使用FilterDispathcer,从Struts 2.1.3开始,它已不推荐使用。如果你使用的Struts的版本 >= 2.1.3,推荐升级到新的Filter,StrutsPrepareAndExecuteFilter。在此研究的是StrutsPrepareAndExecuteFilter。

StrutsPrepareAndExecuteFilter中的方法:

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

web容器一启动,就会初始化核心过滤器StrutsPrepareAndExecuteFilter,并执行初始化方法,初始化方法如下:

public void init(FilterConfig filterConfig) throws ServletException { InitOperations init = new InitOperations(); Dispatcher dispatcher = null; try {  //封装filterConfig,其中有个主要方法getInitParameterNames将配置文件中的初始化参数名字以String格式存储在List中  FilterHostConfig config = new FilterHostConfig(filterConfig);  //初始化struts内部日志  init.initLogging(config);  //创建dispatcher ,并初始化  dispatcher = init.initDispatcher(config);  init.initStaticContentLoader(config, dispatcher);  //初始化类属性:prepare 、execute  prepare = new PrepareOperations(filterConfig.getServletContext(), dispatcher);  execute = new ExecuteOperations(filterConfig.getServletContext(), dispatcher);  this.excludedPatterns = init.buildExcludedPatternsList(dispatcher);  //回调空的postInit方法  postInit(dispatcher, filterConfig); } finally {  if (dispatcher != null) {dispatcher.cleanUpAfterInit();  }  init.cleanup(); }}

关于封装filterConfig,首先看下FilterHostConfig ,源码如下:

public class FilterHostConfig implements HostConfig { private FilterConfig config; //构造方法 public FilterHostConfig(FilterConfig config) {  this.config = config; } //根据init-param配置的param-name获取param-value的值   public String getInitParameter(String key) {  return config.getInitParameter(key); } //返回初始化参数名的迭代器  public Iterator<String> getInitParameterNames() {  return MakeIterator.convert(config.getInitParameterNames()); } //返回Servlet上下文 public ServletContext getServletContext() {  return config.getServletContext(); }}

接下来,看下StrutsPrepareAndExecuteFilter中init方法中dispatcher = init.initDispatcher(config);这是初始化dispatcher的。

public Dispatcher initDispatcher( HostConfig filterConfig ) {  Dispatcher dispatcher = createDispatcher(filterConfig);  dispatcher.init();  return dispatcher;}

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

private Dispatcher createDispatcher( HostConfig filterConfig ) { //存放参数的Map Map<String, String> params = new HashMap<String, String>(); //将参数存放到Map for ( Iterator e = filterConfig.getInitParameterNames(); e.hasNext(); ) {  String name = (String) e.next();  String value = filterConfig.getInitParameter(name);  params.put(name, value); } //根据servlet上下文和参数Map构造Dispatcher  return new Dispatcher(filterConfig.getServletContext(), params);}

这样dispatcher对象创建完成,接着就是dispatcher对象的初始化,打开Dispatcher类,看到它的init方法如下:

public void init() { if (configurationManager == null) {  configurationManager = createConfigurationManager(BeanSelectionProvider.DEFAULT_BEAN_NAME); } try {  init_FileManager();  //加载org/apache/struts2/default.properties  init_DefaultProperties();  //加载struts-default.xml,struts-plugin.xml,struts.xml  init_TraditionalXmlConfigurations();  init_LegacyStrutsProperties();  //用户自己实现的ConfigurationProviders类   init_CustomConfigurationProviders();  //Filter的初始化参数   init_FilterInitParameters() ;  init_AliasStandardObjects() ;  Container container = init_PreloadConfiguration();  container.inject(this);  init_CheckWebLogicWorkaround(container);  if (!dispatcherListeners.isEmpty()) {for (DispatcherListener l : dispatcherListeners) { l.dispatcherInitialized(this);}  } } catch (Exception ex) {  if (LOG.isErrorEnable
源文地址:http://www.guoxiongfei.cn/cntech/17063.html