FilterDispatcher处理流程

1  Struts 2的核心机制

Struts 2的处理流程已经和Struts 1大相径庭了,但是和WebWork比较相似,这都是因为Struts 2和WebWork合并的缘故,并吸取了WebWork大部分设计思想。下面讲解Struts 2的核心流程,以及其他一些处理机制。

2  FilterDispatcher处理流程

在Struts 2中,最重要的一个类是org.apache.struts2.dispatcher.FilterDispatcher,从前面的示例可以看出,用户通 过浏览器提交一个(HttpServletRequest)请求后,请求被在web.xml中定义的过滤器FilterDispatcher拦截,在 FilterDispatcher中主要经过大概3层过滤器的处理,分别是ActionContext CleanUp、其他过滤器(Othter Filters、SiteMesh等)、FilterDispatcher。

在FilterDispatcher过滤器中首先询问ActionMapper是否需要调用某个Action来处理请求,如果 ActionMapper决定需要调用某个Action,FilterDispatcher则把请求的处理交给 ActionProxy,ActionProxy通过配置文件struts.xml找到需要调用的Action类,然后ActionProxy创建一个 ActionInvocation实例并调用该Action,但在调用之前,ActionInvocation会根据配置加载Action相关的所有 Interceptor,等Action执行完毕,ActionInvocation负责根据struts.xml中的配置找到对应的返回结果 result。

在详细介绍FilterDispatcher之前,先讲解一下Servlet中过滤器的概念,以使读者对此有一个深入的认识。过滤器提供一种面向对 象的模块化机制,用以将公共任务封装到可插入的组件中,这些组件通过一个配置文件来声明并动态地处理。实现一个过滤器需要3个步骤:首先编写过滤器实现类 的程序,然后把该过滤器添加到web.xml 中声明,最后把过滤器与应用程序一起打包并部署。

过滤器 API 一共包含 3 个简单的接口:Filter、FilterChain 和 FilterConfig。过滤器类必须实现 Filter 接口:

init():这个方法在容器实例化过滤器时被调用,它主要设计用于使过滤器为处理做准备。容器为这个方法传递一个FilterConfig,其中包含有配置信息。

doFilter():与Servlet拥有一个service()方法来处理请求一样,过滤器拥有单个用于处理请求和响应的方法 doFilter()。这个方法接收3个输入参数: ServletRequest、ServletResponse和FilterChain。FilterChain对于正确的过滤操作至关重 要,doFilter()方法必须调用FilterChain的doFilter()方法,除非该方法用来拦截以后的下游处理。

destroy():该方法由容器在销毁过滤器实例之前调用,以便能够执行任何必需的清理代码。

过滤器通过 web.xml 文件中的两个XML标签来声明。<filter>标签定义过滤器的名称,并且声明实现类和init()参数。<filter- mapping>标签将过滤器与Servlet或URL模式相关联。<filter>标签负责把一个过滤器名和一个特定的类关联起来, 这种关联是通过<filter-name>和<filter-class>元素指定的。<filter>必须有一 个<ulr-pattern>或者<servlet-name>元素,可以通过<ulr-pattern>来指定通 配符,将过滤器应用到Web资源范围;也可以通过<servlet-name>将过滤器指定到某一个特定的Servlet上。应该注意这些声 明的顺序,所引用的过滤器名必须在前面的过滤器定义中给出。下面给出一个过滤器配置的示例代码。


  
 
  
 
  
  
<!--编码过滤器-->   <filter>   <filter-name>SetCharacterEncoding</filter-name>   <filter-class>   com.gd.web.filter.GdSetCharacterEncodingFilter   </filter-class>   <init-param>   <param-name>encoding</param-name>   <param-value>GBK</param-value>   </init-param>   <init-param>   <param-name>ignore</param-name>   <param-value>true</param-value>   </init-param>   </filter>   <!--过滤所有的访问-->   <filter-mapping>   <filter-name>SetCharacterEncoding</filter-name>   <url-pattern>/*</url-pattern>   </filter-mapping> 

然也可以配置多个过滤器,多个过滤器将按照配置的顺序执行。

通过上面的介绍,相信读者对过滤器会有一个深入的了解。打开FilterDispatcher的源代码可以看到,FilterDispatcher 也同样遵循这样的原则,同样实现了init()、doFilter ()、destroy()这3个接口,在init()接口里主要实现了创建Dispatcher和设置默认包的功能,示例代码如下:


  
 
  
 
  
  
public void init(FilterConfig filterConfig) throws ServletException {   try {   this.filterConfig = filterConfig;   //初始化日志   initLogging();   //创建一个Dispatcher   dispatcher = createDispatcher(filterConfig);   dispatcher.init();   dispatcher.getContainer().inject(this);   //设定默认包   staticResourceLoader.setHostConfig(new  FilterHostConfig(filterConfig));   } finally {   ActionContext.setContext(null);   }   }   在destroy()接口里主要实现了销毁Dispatcher和上下文的功能,示例代码如下:   public void destroy() {   //如果Dispatcher为空,则正常结束   if (dispatcher == null) {   log.warn("something is seriously wrong,  Dispatcher is not initialized (null) ");   } else {   try {   //销毁Dispatcher   dispatcher.cleanup();   } finally {   ActionContext.setContext(null);   }   }   } 

在doFilter()接口里主要实现了创建Dispatcher和设置默认包的功能,示例代码如下:


  
 
  
 
  
  
public void doFilter(ServletRequest req, S ervletResponse res, FilterChain chain) throws    IOException, ServletException {   //获取用户请求的request   HttpServletRequest request = (HttpServletRequest) req;   HttpServletResponse response = (HttpServletResponse) res;   ServletContext servletContext = getServletContext();   //加上时间戳   String timerKey = "FilterDispatcher_doFilter: ";   try {   //设定上下文或栈   ValueStack stack = dispatcher.getContainer(). getInstance(ValueStackFactory.class).   createValueStack();   ActionContext ctx = new ActionContext(stack.getContext());   ActionContext.setContext(ctx);   //重新封装request,记录使用的语言、编码方式、是否是上传文件等   UtilTimerStack.push(timerKey);   request = prepareDispatcherAndWrapRequest(request, response);   //获取ActionMapping   ActionMapping mapping;   try {   mapping = actionMapper.getMapping(request,  dispatcher.getConfigurationManager());   } catch (Exception ex) {   //如果没有找到合适的ActionMapping,则抛出异常   dispatcher.sendError(request, response, servletContext, HttpServletResponse.   SC_INTERNAL_SERVER_ERROR, ex);   return;   }   //如果没有配置ActionMapping,则判断是否为静态资源   if (mapping == null) {   //获取访问请求的路径   String resourcePath = RequestUtils.getServletPath(request);   if ("".equals(resourcePath) && null != request.getPathInfo()) {   resourcePath = request.getPathInfo();   }   //判断是否为静态资源   if (staticResourceLoader.canHandle(resourcePath)) {   staticResourceLoader.findStaticResource(resourcePath, request, response);   } else {   // 如果不是,则继续执行下一个过滤器   chain.doFilter(request, response);   }   return;   }   //在正常情况下,调用serviceAction方法   dispatcher.serviceAction(request, response, servletContext, mapping);   //清空上下文和时间戳   } finally {   try {   ActionContextCleanUp.cleanUp(req);   } finally {   UtilTimerStack.pop(timerKey);   }   }   }

转载于:https://my.oschina.net/u/1398304/blog/375433

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值