几个相关的API
- ActionMapping
保存当前Action映射状态的简单类。 - ActionMapper
会返回一个ActionMapping,如果返回的是ActionMapping,说明这是一个Struts2请求,如果返回的是null,说明没有一个action和其匹配,那么这是一个非struts2请求。 - ActionProxy
是XWork和action之间的一个中间层。 - ActionInvocation
Action和各拦截器之间的一个执行状态,利用ActionInvocation去调用各个拦截器,以及执行显示结果。
流程图
一个请求在struts的处理大概有如下的步骤:
- 客户端初始化一个指向Servlet容器(例如Tomcat)的请求;
- 这个请求经过一系列的过滤器(Filter)(有一个叫做
ActionContextCleanUp
的可选过滤器,这个过滤器对Struts2和其它框架的集成很有帮助)。 - 接着
StrutsPrepareAndExecuteFilte
被调用,StrutsPrepareAndExecuteFilter
询问ActionMapper
来决定这个请求是否需要调用某个Action。 - 如果
ActionMapper
决定需要调用某个Action,FilterDispatcher
把请求的处理交给ActionProxy
ActionProxy
通过Configuration Manager
询问框架的配置文件,找到需要调用的Action类ActionProxy
创建一个ActionInvocation
的实例ActionInvocation
实例使用命名模式来调用,在调用Action的过程前后,涉及到相关拦截器的调用- 一旦Action执行完毕,
ActionInvocation
负责根据struts.xml
中的配置找到对应的返回结果,返回结果通常是一个需要被表示的JSP或者FreeMarker的模板。在这个过程中需要涉及到ActionMapper
。 - 接着按照相反次序执行拦截器链(执行Action调用之后的部分)。最后,响应通过过滤器链返回。如果过滤器链中存在
ActionContextCleanUp
,FilterDispatcher
不会清理线程局部的ActionContext
。如果不存在ActionContextCleanUp
过滤器,FilterDispatcher
会清除所有线程局部变量。
源码分析
- 使用Struts2框架都会在web.xml中注册和映射struts2.配置内容如下:
- web容器一启动,就会初始化核心过滤器
StrutsPrepareAndExecuteFilter
,并执行初始化方法。 - 当用户访问某个action的时候,首先调用
StrutsPrepareAndExecuteFilter
的doFilter
方法:该方法是过滤器的执行方法,他拦截提交的HttpServletRequest请求,HttpServletResponse响应,其源码如下:
(1)prepare.createActionContext(request,response)
这是action上下文的创建,ActionContext
是一个容器,这个容器主要存储request、session、application、parameters
等相关信息,ActionContext
是一个线程的本地变量,这意味着不同的action之间不会共享ActionContext
,所以不用考虑线程安全问题。其实质是一个Map,key是表示request 、session等等的字符串,值是对应的对象。
(2)prepare.findActionMapping(request, response, true)
该方法用于获取ActionMapping
对象,Action的配置信息存储在ActionMapping对象中,源码如下:
(3)getMapping()
(4)execute.executeAction(request, response, mapping)
- 如果
mapping
对象不为空,则会执行action,具体调用dispatcher
的serviceAction
方法:
- action代理类的新建是通过
ActionProxyFactory
接口实例来进行的,即是DefaultActionProxyFactory
类的实例,是一个简单的工厂模式。Dispatcher类是重要的调度者,DefaultActionInvocation类是执行Action类实例的行动者,而Action代理类(ActionProxy)则是他们之间的中间人,相当于Dispatcher类通过ActionProxy命令DefaultActionInvocation类去执行Action类实例。
(1)DefaultActionProxy
类:通过DefaultActionProxyFactory
类来创建,然后调用它的prepare()
方法。
(2)初始化DefaultActionInvocation
类的实例,即根据ActionProxy
类实例找到对应的Action类实例(用户自己定义的类)。
ActionProxy
的execute()
方法源码:
DefaultActionInvocation
的invoke()
方法
intercept
方法有一个参数就是DefaultActionInvocation
类的接口,这个参数让struts2的AOP思想能够进行,看一下拦截器的代码,举个LoggingInterceptor
的例子:
拦截器开始的时候,执行相关的拦截器逻辑,然后又重新调用DefaultActionInvocation
类的invoke()
方法,从而获得下一个拦截器,就是这样子下一个拦截器又开始执行自己的intercept
方法。做个相关的拦截器逻辑之后,又一次重新调用了DefaultActionInvocation
类的invoke()
方法,又做了相似的工作,直到没有了拦截器,执行用户action类实例的方法并返回结果,有了结果之后,就开始继续执行当前上一个拦截器的后半部分代码,直到返回最开始的拦截器执行后半部分的代码。
感谢并参考:
https://www.cnblogs.com/java-chen-hao/p/10869984.html