zoukankan      html  css  js  c++  java
  • Struts2请求处理流程及源码分析

    1.1 Struts2请求处理

    1. 一个请求在Struts2框架中的处理步骤:

    a) 客户端初始化一个指向Servlet容器的请求;

    b) 根据Web.xml配置,请求首先经过ActionContextCleanUp过滤器,其为可选过滤器,这个过滤器对于Struts2和其他框架的集成很有帮助(SiteMesh Plugin),主要清理当前线程的ActionContext和Dispatcher;

    c) 请求经过插件过滤器,如:SiteMesh、etc等过滤器;

    d) 请求经过核心过滤器FilterDispatcher,执行doFilter方法,在该方法中,询问ActionMapper来决定这个请求是否需要调用某个Action;

    e) 如果ActionMapper决定需要调用某个Action,则ActionMapper会返回一个ActionMapping实例(存储Action的配置信息),并创建ActionProxy(Action代理)对象,将请求交给代理对象继续处理;

    f) ActionProxy对象根据ActionMapping和Configuration Manager询问框架的配置文件,找到需要调用的Action类;

    g) ActionProxy对象创建时,会同时创建一个ActionInvocation的实例;

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

    i) 一旦Action执行完毕,ActionInvocation实例负责根据struts.xml中的配置创建并返回Result。Result通常是一个需要被表示的JSP或者FreeMarker的模版,也可能是另外的一个Action链;

    j) 如果要在返回Result之前做些什么,可以实现PreResultListener接口,PreResultListener可以在Interceptor中实现,也可以在Action中实现;

    k) 根据Result对象信息,生成用户响应信息response,在生成响应过程中可以使用Struts2 框架中继承的标签,在此过程中仍会再次涉及到ActionMapper;

    2. Struts2请求处理示意图:

    clip_image002

    1.2 Struts2请求处理源码分析

    当用户向Struts2发送请求时,FilterDispatcher的doFilter()方法自动调用,doFilter()方法处理请求过程,如下:

    1. 创建值栈对象stack;

    2. 创建Action上下文对象;

    3. 对请求进行重新封装,此次封装根据请求内容的类型不同,返回不同的对象:

    如果为multipart/form-data类型,则返回MultiPartRequestWrapper类型的对象,该对象服务于文件上传,否则返回StrutsRequestWrapper类型的对象,MultiPartRequestWrapper是StrutsRequestWrapper的子类,而这两个类都是HttpServletRequest接口的实现。

    4. 通过actionMapper.getMapping()获得ActionMapping对象,Action的配置信息存储在ActionMapping对象中(Action的配置信息:Action的name、namespace和要调用的方法method)。相关代码如下图所示:

    clip_image004

    以上代码,活动图如下:

    clip_image006

    5. 如果getMapping()方法返回ActionMapping对象为null,则FilterDispatcher认为用户请求不是Action,此时FilterDispatcher会首先分析:

    如果请求以/struts开头,会自动查找在web.xml文件中配置的packages初始化参数,FilterDispatcher会将packages参数值包下的文件当作静态资源处理,即直接在页面上显示文件内容。

    如果用户请求的资源不是以/struts开头—可能是.jsp文件,也可能是.html文件,则通过过滤器链继续往下传送,直到到达请求的资源为止。

    6. 如果getMapping()方法返回有效的ActionMapping对象,则被认为正在请求某个Action,将调用Dispatcher.serviceAction(request, response, servletContext, mapping)方法。

    以上六步,相关代码如下图所示:

    clip_image008

    clip_image010

    以上代码,活动图如下:

    clip_image012

    7. 请求进入dispatcher.serviceAction(request,response,servletContext,mapping)方法中:

    a) 将相关对象信息封装为Map(如:HttpServletRequest、Http parameters、HttpServletResponse、HttpSession、ServletContext、ActionMapping等对象信息),并存入到执行上下文Map中,返回执行上下文Map对象extraMap;

    b) 获取mapping对象中存储的action命名空间、name属性、method属性等信息;

    c) 加载并解析Struts2配置文件,如果没有人为配置,默认按顺序加载struts-default.xml、struts-plugin.xml、struts.xml,将action配置、result配置、interceptor配置,解析并存入至config对象中,返回文件配置对象config;

    d) 根据执行上下文Map、action命名空间、name属性、method属性等创建用户Action的代理对象;

    e) 执行Action代理对象proxy.execute()方法,并转向结果;

    以上步骤相关代码,如图所示:

    clip_image014

    8. 执行Action代理对象proxy.execute()方法,该方法的执行,其实就是调用了invocation.invoke()方法,如下图所示:

    clip_image016

    9. 执行invocation.invoke()方法,实现了截拦器的递归调用和执行Action的execute()方法,DefaultActionInvocation.invoke()方法中代码,如下图所示:

    clip_image018

    在以上代码中,并未看出拦截器的递归调用,其实是否递归调用,是由程序员来控制的,递归调用实现很简单:

    a) 首先看下Interceptor接口定义:

    clip_image020

    b) 所有的截拦器必须实现intercept方法,而该方法的参数恰恰又是ActionInvocation,所以如果在intercept方法中调用invocation.invoke(),则会继续从Action的Intercepor列表中找到下一个截拦器执行,依此递归调用Intercepor;

    Struts2中的日志拦截器LoggingInterceptor,如下图所示:

    clip_image022

    c) 拦截器递归调用活动图,如下所示:

    clip_image024

    10. 在invocation.invoke()方法中,执行拦截器、action并获得resultCode完毕后,则会继续执行PreResultListener集合,并生成Result对象,实现PreResultListener接口,可在返回Result之前,做些自定义处理,如图所示

    clip_image026

    在返回Result之前,通过PreResultListener实现自定义处理,常用的有两种方式:一种在Interceptor中实现,一种在Action实现,如图所示:

    clip_image028

    clip_image030

    以上两种方式,大家可以发现都是通过匿名内部类的方式实现,其实还有一种方式就是通过在拦截器中实现PreResultListener接口,并实现方法beforeResult方法,即可。如下图所示:

    clip_image032

    11. 最后,通过生成Result完成用户响应;

    以上1-11步,为Struts2处理请求的完整流程分析,其相关代码调用流程,如下图所示:

    clip_image034

    原文链接:http://my.oschina.net/xianggao/blog/75514

  • 相关阅读:
    Why Choose Jetty?
    Jetty 的工作原理以及与 Tomcat 的比较
    Tomcat设计模式
    Servlet 工作原理解析
    Tomcat 系统架构
    spring boot 打包方式 spring boot 整合mybaits REST services
    wireshark udp 序列号 User Datagram Protocol UDP
    Maven 的聚合(多模块)和 Parent 继承
    缓存策略 半自动化就是mybaitis只支持数据库查出的数据映射到pojo类上,而实体到数据库的映射需要自己编写sql语句实现,相较于hibernate这种完全自动化的框架我更喜欢mybatis
    Mybatis解决sql中like通配符模糊匹配 构造方法覆盖 mybits 增删改
  • 原文地址:https://www.cnblogs.com/dangzhenjiuhao/p/5344308.html
Copyright © 2011-2022 走看看