用了几天模拟struts2,最后结果还是很成功的,也基本没有什么遇上比较难解决的问题,万事开头难,在最开始的时候无从下手,看着下面这张struts2工作流程图配合着网上的博客看了一天终于有了眉目。
看到图的时候应该最先看图例:第一个橙色(Servlet Filter)表示过滤器;第二个蓝色的(Struts Core)表示struts2的核心,是struts2最重要的部分;第三个(Interceptors)表示拦截器,是struts2中一个运用的很好的一个地方;最后一个(User created)是用户自己需要书写的代码
struts2的入口是什么?这个问题曾经把我问住了。现在想想如果这张图深深地记住,那么struts2的基本工作流程也就明白了。struts2的入口是过滤器,一个HttpServletRequest进来首先是过滤器,注意是过滤器,在图上我们也可以看到,用户发起的请求首先进入到过滤器,有些时候感觉过滤器是struts2的基础,但是这么说有些绝对,struts2因为有了过滤器,让有些代码变得简单。Struts实际上使用了一个所谓的ServletFilter来“使事情有效”。一般来说,使用Struts 2时不需要编写Servlet。在模拟struts2的时候需要自己定义一个过滤器,自定义的过滤器需要实现Filter接口,在doFilter方法中写入自己定义的规则基本上这个过滤器就可以使用了,注意需要在web.xml文件中进行配置,我们在开发struts2项目的时候也是需要在web.xml文件中配置一下,定义过滤器需要过滤哪些信息,只有经过过滤器选择出来需要进入struts2框架中处理的才会进入,其他的直接跳转到指定页面。自己定义了一个LoginFilter,在下面的配置中需要指定过滤器类,在url-patten中定义过滤的规则,/*代表所有的请求都会过滤。
<filter> <filter-name>LoginFilter</filter-name> <filter-class>com_filter.LoginFilter</filter-class> </filter> <filter-mapping> <filter-name>LoginFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>在过滤器类中是可以执行跳转页面代码的,在上面也说到了在使用struts2的时候不需要编写Servlet,struts2主要是把Servlet隐藏了,Servlet主要是执行了从一个页面到另一个页面的跳转,而过滤器是可以完全代替这些功能的,在过滤器的diFilter方法中声明了ServletRequest和ServletResponse两个类型的参数req、resp,在需要使用跳转的的时候把这两个参数强转成HttpServletRequest和HttpResponse类型的参数即可。在struts2源码中可见:
HttpServletRequest request = (HttpServletRequest)req; HttpServletResponse response = (HttpServletResponse)res;接着向下,经过过滤器的请求到了ActionMapper,但是ActionMapper只是简单的判断,在上面的过滤器中讲到了判断此时的请求是否过滤掉,这个ActionMapper是判断经过过滤器的请求是否需要struts2处理,也就是判断调用哪个Action。ActionMapper其实是HttpServletRequest和Action调用请求的一个映射,它屏蔽了Action对于Request等javaServlet类的依赖。Struts2中它的默认实现类是DefaultActionMapper。
在struts2的工作流程图中可以看到ActionMapper处理之后又返回给了FilterDispatcher,让FilterDispatcher把请求交给ActionProxy,最终调用还是由ActinProxy调用,注意ActionProxy是一个代理类,这里用到了动态代理这种设计模式,我的关于代理模式的文章:Java设计模式-代理模式,在模拟这里的时候代码,其实动态代理我们接触的很少,代码结构很不熟悉。ActionProxy通过ConfigurationManager读取了struts.xml配置文件,这里就要用到xml解析,通过对xml配置文件的解析,读出数据,包括Action类及做出响应的页面等信息。
ActionProxy通过ActionInvocation来执行用户请求对应Acion的拦截器。ActionInvocation负责管理拦截器(Interceptor)。在拦截器这里又用到了责任链设计模式,详见我的责任链的文章:Java设计模式-责任链模式,关于责任链还是比较好理解的,把不同的处理都放在拦截器中,然后组建成一条链,让用户的请求在这条链上走一遍完成各个不同的处理。
在<interceptors>标签中定义了拦截器类的名字和对应的类
然后在<interceptor-stack>中配置拦截器栈,这里相当于数据结构中的栈,从第一个走到最后,想要返回还要从最后一个依次返回,实际上struts2中调用的拦截器就是这些拦截器栈,用户也可以自己定义拦截器栈,把想要的功能组成一个interceptor-stack
在struts2的源码中struts-default.xml文件中配置了好多拦截器。模拟这里的时候,关于读出Action类,这里主要用到了反射,利用反射对类中的属性赋值及执行方法。
最后的返回的结果HttpServletResponse还是要通过过滤器返回的,在模拟的时候,把一些处理的调用放在了过滤器中这样在返回的时候就可以在过滤器中返回。实际上struts2的类远远不止这些,看到仔细的分析,写出了30多个类。简单的模拟只是实现了表单内容验证登录,很多东西都是写死的。