本文适合学过和用过struts2的人。(转载:https://zhuanlan.zhihu.com/p/50245867)
首先不多bb,上一张struts2的架构图,看着架构图对应着源码分析
1、StrutsPrepareAndExecuteFilter: struts2的核心过滤器,作用:拦截请求。
2、ActionMapper:核心过滤器会调用ActionMapper处理请求过来的url,看该请求是否需要
struts2来进行处理,如果需要会返回一个ActionMapping对象里面包含了
actionName,namespace等。
3、ActionProxy: 可以把它当作一个老板,ActionInvocation当作它的秘书,它会调用
ConfigurationManager去读取struts.xml的配置。
4、ConfigurationManager: 读取struts.xml的配置,struts.xml在内存中的映射。
5、struts.xml:这个就不用说了,是Stuts2的应用配置文件,负责诸如URL与Action之间映射关系
的配置、以及执行后页面跳转的Result配置等。
6、ActionInvocation: 作用是通过老板给的actionName,namespace等信息,调用对应的
Action,当然执行之前先执行拦截器
7、Interceptor: struts2的拦截器,默认20个,都是有着很重要的作用,比如参数拦截器(把
请求过来的参数封装到对应的Action属性中),模型驱动拦截器(把请求参数封装成一个
对象)。
其他的就不介绍了,一看就懂
首先先搭建好struts2的运行环境,引入jar包,配置核心拦截器,什么的就不说了。
Action
perfect.jsp(转发的页面)
自定义拦截器
一.
首先在StrutsPrepareAndExecuteFilter中的doFilter方法中打个断点并访问action进入doFilter方法
这里的代码就是判断该请求是否归struts2来处理,不归struts2管的话就直接doFilter放行,显然我们这里是需要struts2来处理的请求,所以进行下一步。
二.
程序执行到这一行看字面意思就知道是创建 数据中心,就是包含了很多数据的一个map,比如request,response,session等。这里我们进入这个方法看下到底做了什么
三.
这里我检几个重要的代码给大家看下,第一个圈出来的就是获取数据中心,第二个判断如果之前没有数据中心,我们就创建一个值栈ValueStack,学过struts2的就知道值栈中有个栈,还有个context(Map),接下来看它执行了什么呢,根据request,response创建一个contextMap,put给值栈中的Context,然后再把ValueStack中的Context的获取出来实例化ActionContext,也就是数据中心并返回。下面我们再回来继续走我们的核心过滤器
四 .
走到核心过滤器这里,我们看到了一个wrapRequest方法,就是包装request对象,学过struts2的就知道,在action中获得到的request就是被包装过的,可以看到没有执行这个方法之前这个request属于org.apache.catalina.connector这个包下。执行这个方法之后呢,竟然变成了org.apache.struts2.dispatcher.StrutsRequestWrapper类,那我们进入这个类中看到底包装了什么呢?
五.
看这个request中的包装类到底对什么进行了包装呢,发现里面的getAttribute方法有点猫腻,方法中先调用了父类的getAttribute方法,那我们看它父类到底是谁呢?
就是原生的request对象,接着我们在看下面执行了什么。
意思是如果ActionContext不为空且从原生request中获取到的值为null,我们就去值栈中获取值,调用findValue方法。再根据我们之前学的ognl表达式中,是不是通过一个类的属性就能去值栈中的栈中找到对应的值。由此我们可以推断出在request中取值,首先会在原生request
中找,找不到再去值栈中找,现在值栈中的栈中找,再去Context域中找。
六.
接着我们再回来继续执行核心过滤器中的代码
对应上面所说的会调用ActionMapper处理请求如果需要struts2处理这个请求就会返回一个mapping对象,不会就会放行,这里很明显mapping中封装了actionName和namespace等信息。
七.
接下来进入executeAction方法中看下。
在进入serviceAction方法
这里根据mapping中的信息创建老板对象,下面老板给mapping中的信息让ActionInvocation(秘书)去执行拦截器和action,我们进入execute方法。
八.
再进入秘书执行拦截器的方法
判断这个是否还有拦截器,这里不用while循环而用了if,是因为把秘书对象传给拦截器中的intercept方法,方法中又递归调用了秘书的invoke方法,所以直到调用完拦截器才会执行Action。
配置拦截器的时候,先配置了自定义的所以就执行了拦截器的前处理,然后放行,执行完系统的20个拦截器后,最终执行到Action中。
九.
最终返回结果跳转到视图,进行渲染,然后进行拦截器的后处理。
为什么这样配置就会跳转到页面中呢,持续关注,下次分析源码解释。