FilterDispatcher处理流程

1  Struts 2的核心机制 web

Struts 2的处理流程已经和Struts 1截然不同了,可是和WebWork比较类似,这都是由于Struts 2和WebWork合并的缘故,并吸收了WebWork大部分设计思想。下面讲解Struts 2的核心流程,以及其余一些处理机制。 apache

2  FilterDispatcher处理流程 浏览器

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

在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 中声明,最后把过滤器与应用程序一块儿打包并部署。 this

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

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

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

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上。应该注意这些声 明的顺序,所引用的过滤器名必须在前面的过滤器定义中给出。下面给出一个过滤器配置的示例代码。

 
  1. <!--编码过滤器-->  
  2. <filter>  
  3. <filter-name>SetCharacterEncoding</filter-name>  
  4. <filter-class>  
  5. com.gd.web.filter.GdSetCharacterEncodingFilter  
  6. </filter-class>  
  7. <init-param>  
  8. <param-name>encoding</param-name>  
  9. <param-value>GBK</param-value>  
  10. </init-param>  
  11. <init-param>  
  12. <param-name>ignore</param-name>  
  13. <param-value>true</param-value>  
  14. </init-param>  
  15. </filter>  
  16. <!--过滤全部的访问-->  
  17. <filter-mapping>  
  18. <filter-name>SetCharacterEncoding</filter-name>  
  19. <url-pattern>/*</url-pattern>  
  20. </filter-mapping> 

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

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

 
  1. public void init(FilterConfig filterConfig) throws ServletException {  
  2. try {  
  3. this.filterConfig = filterConfig;  
  4. //初始化日志  
  5. initLogging();  
  6. //建立一个Dispatcher  
  7. dispatcher = createDispatcher(filterConfig);  
  8. dispatcher.init();  
  9. dispatcher.getContainer().inject(this);  
  10. //设定默认包  
  11. staticResourceLoader.setHostConfig(new  FilterHostConfig(filterConfig));  
  12. finally {  
  13. ActionContext.setContext(null);  
  14. }  
  15. }  
  16. 在destroy()接口里主要实现了销毁Dispatcher和上下文的功能,示例代码以下:  
  17. public void destroy() {  
  18. //若是Dispatcher为空,则正常结束  
  19. if (dispatcher == null) {  
  20. log.warn("something is seriously wrong,  Dispatcher is not initialized (null) ");  
  21. else {  
  22. try {  
  23. //销毁Dispatcher  
  24. dispatcher.cleanup();  
  25. finally {  
  26. ActionContext.setContext(null);  
  27. }  
  28. }  

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

 
  1. public void doFilter(ServletRequest req, S ervletResponse res, FilterChain chain) throws   
  2. IOException, ServletException {  
  3. //获取用户请求的request  
  4. HttpServletRequest request = (HttpServletRequest) req;  
  5. HttpServletResponse response = (HttpServletResponse) res;  
  6. ServletContext servletContext = getServletContext();  
  7. //加上时间戳  
  8. String timerKey = "FilterDispatcher_doFilter: ";  
  9. try {  
  10. //设定上下文或栈  
  11. ValueStack stack = dispatcher.getContainer(). getInstance(ValueStackFactory.class).  
  12. createValueStack();  
  13. ActionContext ctx = new ActionContext(stack.getContext());  
  14. ActionContext.setContext(ctx);  
  15. //从新封装request,记录使用的语言、编码方式、是不是上传文件等  
  16. UtilTimerStack.push(timerKey);  
  17. request = prepareDispatcherAndWrapRequest(request, response);  
  18. //获取ActionMapping  
  19. ActionMapping mapping;  
  20. try {  
  21. mapping = actionMapper.getMapping(request,  dispatcher.getConfigurationManager());  
  22. catch (Exception ex) {  
  23. //若是没有找到合适的ActionMapping,则抛出异常  
  24. dispatcher.sendError(request, response, servletContext, HttpServletResponse.  
  25. SC_INTERNAL_SERVER_ERROR, ex);  
  26. return;  
  27. }  
  28. //若是没有配置ActionMapping,则判断是否为静态资源  
  29. if (mapping == null) {  
  30. //获取访问请求的路径  
  31. String resourcePath = RequestUtils.getServletPath(request);  
  32. if ("".equals(resourcePath) && null != request.getPathInfo()) {  
  33. resourcePath = request.getPathInfo();  
  34. }  
  35. //判断是否为静态资源  
  36. if (staticResourceLoader.canHandle(resourcePath)) {  
  37. staticResourceLoader.findStaticResource(resourcePath, request, response);  
  38. else {  
  39. // 若是不是,则继续执行下一个过滤器  
  40. chain.doFilter(request, response);  
  41. }  
  42. return;  
  43. }  
  44. //在正常状况下,调用serviceAction方法  
  45. dispatcher.serviceAction(request, response, servletContext, mapping);  
  46. //清空上下文和时间戳  
  47. finally {  
  48. try {  
  49. ActionContextCleanUp.cleanUp(req);  
  50. finally {  
  51. UtilTimerStack.pop(timerKey);  
  52. }  
  53. }  
  54. }
相关文章
相关标签/搜索