struts2 请求采用什么机制处理客户请求?

C:(controller)控制器 & & & & &M:(model)模型处理 & &V:(view)视图
Struts 2 的运行过程:
& & 核心控制器是FilterDispatcher会过滤所有的请求,如果请求以 action结尾,该请求会转入框架处理。当框架获取*action请求后,根据*action的前半部分决定调用哪个业务逻辑组件。最后根据业务逻辑组件的处理信息决定转发到哪个视图;
& & Struts2有三部分组成:核心控制器是FilterDispatcher,业务控制器和业务逻辑组件组件,其中核心控制器FilterDispatcher由Struts2提供,而业务逻辑控制器和业务逻辑组件要用户自己实现。
& 核心控制器FilterDispatcher:负责拦截所有用户的请求,如果用户的请求以action结尾,该请求就会转入Struts2框架处理。
&业务控制器组件:实现Action类的实例(或者继承了ActionSupport的实例),该类经常能够返回一个字符串(逻辑视图&result&的execute方法,用来实现业务控制)。
&业务逻辑组件:一般由javaBean或者EJB实现;
在Struts2中处理用户请求的并不是业务逻辑,而是Action代理:过程是这样的,在Struts2框架中有一系列的拦截器,这些拦截器将HttpServletRequest请求中的参数分析出来,传入Action中,并回调execute()方法来处理用户请求。
所有的请求被拦截器拦截时:执行流程
1,FilterDispatcher会将所有的请求转发给
ActionProxy(Action代理),Action代理会根据配置文件struts.xml决定转发给那个Action;
2,在请求转发给Action的过程中,会经过一系列拦截器,这些拦截器负责将请求解析并转发给相应的Action。
3,经过相应的Action的
execute()方法处理,会得到一个
视图名的结果集,根据结果结合相应的模版产生相应的输出流。
4,输出流也可以经过一些列的拦截器后,传给浏览器。
对于源码根据图的理解:在Struts2的doFilter()方法中,通过execute.executeAction(request, response, mapping)执行进入了Dispatcher,生成了Dispatcher的对象,并调用了serviceAction()方法;接下里调用了create()方法生成ActionProxy的对象proxy ,通过proxy调用了Actioninvaction的的invoke()方法,接下里,Actioninvaction调用interceptor()方法,然后再 继续调用invoke()方法返回,判断是否interceptor()调用完成,直到所有的interceptor()方法调用完成,就执行*Action所对应的execute().
模拟Struts2 实现的全过程代码;
public class Main
public static void main(String[] args)
&&&&&&&&&&&&&&&&
new ActionInvaction().invoke();
public interface Interceptor
public void interceptor(ActionInvaction invaction);
public class FristInterceptor implements Interceptor
public void interceptor(ActionInvaction invaction)
System.out.println(1);
invaction.invoke();
System.out.println(-1);
public class SecondInterceptor implements Interceptor
public void interceptor(ActionInvaction invaction)
System.out.println(2);
invaction.invoke();
System.out.println(-2);
public class ActionInvaction
List&Interceptor& interceptors = new ArrayList&Interceptor&();
int index = -1;
Action a = new Action();
public ActionInvaction()
this.interceptors.add(new FristInterceptor());
this.interceptors.add(new SecondInterceptor());
public void invoke()
if(index &= interceptors.size())
a.execute();
this.interceptors.get(index).interceptor(this);
public class Action
public void execute()
System.out.println("execute!!!");
阅读(...) 评论()Struts2简介
& & & &Struts 2框架作为Struts 1.X框架的替代技术,相对Struts 1.X来说,有着本质上的改变, Struts 2框架是从WebWork框架发展而来的.Apache Struts 2即是大家之前所熟悉的webwork2.随着各自的发展,webwork和Struts社区决定将二者合并为Struts2,新版本的Struts与以前版本一样更易于使用。从某种程度上来讲,Struts2没有继承Struts1的血统,而是继承了webwork的血统并且吸收了Struts1和webwork两者的优势,所以说Struts2并不是一个全新的框架。
mvc设计模式& & &&
& & &&谈到Struts就不得不谈谈mvc设计模式。mvc设计模式是一种目前广泛应用的软件设计模式。随着网络应用的快速发展,应用变得越来越复杂,mvc设计模式为应用模型提供了最基本的分析方法,为构造产品提供了清晰的设计框架,为软件工程提供规范的依据。
& & mvc设计模式将应用程序划分为模型层、视图层、控制器。
模型层包括业务逻辑和数据访问层,在整个mvc模型中Model部分就是业务流程或状态的处理以及业务规则的制定,可以说是mvc中最重要的部分。
& & 视图,一个web项目中可能有很多不同的视图,mvc设计模式对于视图的处理仅限于视图上数据的采集和处理以及响应用户的请求,而不包括在视图上的业务流程的处理。
& & 控制器,控制器在视图层与业务逻辑层之间起到了桥梁作用,控制了两者之间的数据流向。当用户请求从V部分传到控制器时,控制器调用相应的模型层在控制器中进行处理。控制器再将处理结果转发给适当的视图层,循环进行此过程。
& & mvc工作流程:
& & 1.用户的请求提交给控制器
& & 2.控制器受到用户请求后根据用户的具体需求,调用相应的模型(javabean或者EJB)来处理用户请求。
& & 3.控制器调用模型层进行数据处理后,根据处理结果进行下一步的跳转,如跳转到另一个视图或其他控制层。
struts2工作原理
& & & &Struts2是基于mvc设计模式的java web框架技术之一,Struts2框架按照mvc的设计思想把java web 应用程序分为:控制层(核心控制器和业务控制器)、模型层(业务逻辑组件和数据库访问组件)、视图层(包括HTML、JSP、Struts2的表签)。
& & && & &1.客户提交请求道服务器
& & & & 2.请求被提交到一系列的过滤器或者拦截器,最后到达FilterDispather
& & & & 3.FilterDispather读取配置文件struts.xml,根据配置信息调用某个Action来处理客户请求。
& & & & 4.Action处理后,返回结果,FilterDispather根据struts.xml的配置找到对应的页面跳转。
核心控制器
& & & &Struts2的成功因素之一在于核心控制器FilterDispather,该控制器作为一个过滤器运行在java web项目中,负责拦截所有用户请求,当用户请求到达时,该过滤请求会过滤用户请求。FilterDispather负责四个方面的功能:
   (1)执行Actions
   (2)清除ActionContext
   (3)维护静态内容
   (4)清除request生命周期内的XWork的interceptors
业务控制器
& & & &Struts2的成功的另一个因素在于Action业务逻辑控制器。开发基于Struts2的java web 应用项目时,Action是数据处理的核心,需要编写大量的Action类,并在struts.xml文件中配置Action。Action类中包含了对用户请求的处理逻辑,因此也把Action称为Action业务控制器。它是用户请求和业务逻辑之间的桥梁,每个Action充当客户的业务代理。
& & & &Struts2紧紧围绕两大核心控制器,做到了根据请求的参数转发请求给适当的控制器、在控制器中调用业务接口、将业务接口返回的结果包装起来发送给指定的视图,并由视图完成处理结果的展现,使得开发模块化、降低耦合、更易于扩展。当然Struts2的一些细节好处就更不用说了,例如获取表单内容,并组织生成参数对象、易于扩展的插件机制。
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:103216次
积分:5176
积分:5176
排名:第1702名
原创:97篇
评论:1618条
(3)(3)(1)(3)(3)(1)(2)(2)(3)(4)(2)(4)(2)(4)(4)(4)(4)(4)(4)(4)(4)(3)(5)(4)(4)(4)(4)(2)(2)(4)程序员薪资调查、统计版块发布,呼吁大家积极参与,你的投票对自己和他人都会有所帮助。
&&>>&&博客
共34个博文 ,已有21219次阅读
你的薪资高吗?
&dA最新博文
如果想要修改布局可直接修改capt...
twitter的申请部分,这里就不在说了,大家可以...
由于最近在做一个联想的android app,涉及...
win8的磁贴效果,上图:
Java 8刚刚在几周前的3月18日发布。几天后,...
,已有691次阅读 ,共0个评论
网上对于struts2请求处理流程的讲解还是比较多的,有的还是非常详细的,所以这里我就简单地将大概流程总结下,有了个大概印象后理解起源码就会有一定的思路了:
struts2的请求处理过程实际上是在初始化中加载的配置及容器的基础上,通过请求的url分析出命名空间、action名称、方法名称,在利用命名空间检索出该命名空间下配置的所有antion,在通过action名称找到具体的action,生成action实例,如果该action上配置了拦截器则依次调用拦截器,之后调用action中方法名称指定的方法,最后通过配置中的result返回相应视图。
版本:struts2-2.1.6 &xwork-2.1.2
下面就通过源码进行分析下:
struts2中处理请求是通过过滤器org.apache.struts2.dispatcher.FilterDispatcher的doFilter()方法实现的,如下:
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest)
HttpServletResponse response = (HttpServletResponse)
ServletContext servletContext = getServletContext();
String timerKey = "FilterDispatcher_doFilter: ";
// FIXME: this should be refactored better to not duplicate work with the action invocation
ValueStack stack = dispatcher.getContainer().getInstance(ValueStackFactory.class).createValueStack();
ActionContext ctx = new ActionContext(stack.getContext());
ActionContext.setContext(ctx);
UtilTimerStack.push(timerKey);
request = prepareDispatcherAndWrapRequest(request, response);
mapping = actionMapper.getMapping(request, dispatcher.getConfigurationManager());
} catch (Exception ex) {
log.error("error getting ActionMapping", ex);
dispatcher.sendError(request, response, servletContext, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, ex);
if (mapping == null) {
// there is no action in this request, should we look for a static resource?
String resourcePath = RequestUtils.getServletPath(request);
if ("".equals(resourcePath) && null != request.getPathInfo()) {
resourcePath = request.getPathInfo();
if (staticResourceLoader.canHandle(resourcePath)) {
staticResourceLoader.findStaticResource(resourcePath, request, response);
// this is a normal request, let it pass through
chain.doFilter(request, response);
// The framework did its job here
dispatcher.serviceAction(request, response, servletContext, mapping);
} finally {
ActionContextCleanUp.cleanUp(req);
} finally {
UtilTimerStack.pop(timerKey);
前2句比较简单,向上转换req、res为标准接口HttpServletRequest、HttpServletResponse形式。req是org.apache.catalina.connector.RequestFacade的实例,RequestFacade实现了接口HttpServletRequest,而HttpServletRequest继承自ServletRequest接口。第3句,获得servletContext即servlet上下文,通过上下文对象可以访问web.xml描述文件的初始化参数。第4句定义timerKey变量,值是将当前过滤器的类名和当前方法名拼接起来,看下下面的代码发现timerKey用于UtilTimerStack.push(timerKey)和UtilTimerStack.pop(timerKey)俩句,其实这俩句并不属于处理流程的功能代码,而是性能代码,主要是监测下doFilter()方法的执行时间,然后通过日志打印出来,所以这俩句可以不用理会。ValueStack stack = dispatcher.getContainer().getInstance(ValueStackFactory.class).createValueStack()句,首先通过dispatcher.getContainer().getInstance(ValueStackFactory.class)从容器中获得type(类型)为ValueStackFactory.class的bean,然后调用该bean的createValueStack()创建一个ValueStack实例。ValueStackFactory.class默认情况下是使用struts-default.xml配置中的&&bean type="com.opensymphony.xwork2.util.ValueStackFactory" name="struts" class="com.opensymphony.xwork2.ognl.OgnlValueStackFactory" /&,即通过上面的容器返回的是个com.opensymphony.xwork2.ognl.OgnlValueStackFactory实例,从名字看出其是个ValueStack工厂,通过调用该工厂的createValueStack()方法返回ValueStack实例。
ValueStack就是通常所说的"值栈",系统每次请求时都会创建个新的ValueStack,其中会保存着本次请求处理的所有中间数据,如:请求的action实例、各种servlet内置对象(request、response、session、application等)、请求参数等。F5看下定义:
public interface ValueStack {
public static final String VALUE_STACK = "com.opensymphony.xwork2.util.ValueStack.ValueStack";
public static final String REPORT_ERRORS_ON_NO_PROP = "com.opensymphony.xwork2.util.ValueStack.ReportErrorsOnNoProp";
public abstract Map&String, Object& getContext();
public abstract void setDefaultType(Class defaultType);
public abstract void setExprOverrides(Map&Object, Object& overrides);
public abstract Map&Object, Object& getExprOverrides();
public abstract CompoundRoot getRoot();
public abstract void setValue(String expr, Object value);
public abstract void setValue(String expr, Object value, boolean throwExceptionOnFailure);
public abstract String findString(String expr);
public abstract Object findValue(String expr);
public abstract Object findValue(String expr, Class asType);
public abstract Object peek();
public abstract Object pop();
public abstract void push(Object o);
public abstract void set(String key, Object o);
public abstract int size();
是个接口,因为ValueStack本身是堆栈,所以我们看到peek()、pop()、push()等堆栈方法都是有的,其中有个最重要的方法getContext()和getRoot(),getContext()返回的是个Map&String, Object&类型,一般请求中的参数、servlet各种内置对象都是存放在这个Map中。getRoot()返回的就是堆栈数据实际存放的地方,peek()、pop()、push()都是基于其操作的。CompoundRoot是个堆栈类,它继承了java.util.ArrayList,并以此为基础实现了peek()、pop()、push()方法,从而可以独立的作为堆栈使用。这样的话ValueStack就不必在单独实现堆栈功能,只需要在内部创建个CompoundRoot实例就可,其peek()、pop()、push()方法直接调用CompoundRoot的相应方法即可,实际上struts2中的ValueStack默认实现类就是这样做的。另外在这个堆栈中保存的最典型的数据就是action实例。有ognl知识的朋友知道,ognl中基于搜索的有俩个重要对象:上下文和根对象,实际上struts2在利用ognl时,是将getContext()获得的对象作为ognl的上下文、getRoot()获得的作为根对象。这就是为什么我们在通过struts2标签访问action中属性数据时不需要加"#",而访问request、response、session中数据时需要加"#"的原因了。因为ognl中访问根对象是不需要加"#"的,而访问上下文是需要加"#"的。为了更好的理解这块,建议大家先学习下ognl的使用方法及特性。为了验证上面的说法,我举个例子,看下struts2的&s:property value=""/&标签是如何使用ValueStack的,以及最后如何调用ognl的。
这里还要事先交代下,在处理流程的后面处理中会将ValueStack(引用)存于俩个地:一个是ActionContext,另一个是通过request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, valuesStack)将ValueStack存于request中。&s:property value=""/&标签中使用的ValueStack是通过request获得的。下面看下&s:property value=""/&标签的源码,从struts2的标签定义文件struts-tags.tld中查到,该标签对应的类是org.apache.struts2.views.jsp.PropertyTag,如下:
public class PropertyTag extends ComponentTagSupport {
private static final long serialVersionUID = 743852L;
private String defaultV
private boolean escape =
private boolean escapeJavaScript =
public Component getBean(ValueStack stack, HttpServletRequest req, HttpServletResponse res) {
return new Property(stack);
protected void populateParams() {
super.populateParams();
Property tag = (Property)
tag.setDefault(defaultValue);
tag.setValue(value);
tag.setEscape(escape);
tag.setEscapeJavaScript(escapeJavaScript);
public void setDefault(String defaultValue) {
this.defaultValue = defaultV
public void setEscape(boolean escape) {
this.escape =
public void setEscapeJavaScript(boolean escapeJavaScript) {
this.escapeJavaScript = escapeJavaS
public void setValue(String value) {
this.value =
我们要找下标签的doStartTag(),这个方法会在标签被处理前调用。关于标签这块,建议大家先学下jsp自定义标签的使用。&
去它的父类ComponentTagSupport中找下:
public abstract class ComponentTagSupport extends StrutsBodyTagSupport {
protected C
public abstract Component getBean(ValueStack stack, HttpServletRequest req, HttpServletResponse res);
public int doEndTag() throws JspException {
component.end(pageContext.getOut(), getBody());
component =
return EVAL_PAGE;
public int doStartTag() throws JspException {
component = getBean(getStack(), (HttpServletRequest) pageContext.getRequest(), (HttpServletResponse) pageContext.getResponse());
Container container = Dispatcher.getInstance().getContainer();
container.inject(component);
populateParams();
boolean evalBody = component.start(pageContext.getOut());
if (evalBody) {
return component.usesBody() ? EVAL_BODY_BUFFERED : EVAL_BODY_INCLUDE;
return SKIP_BODY;
protected void populateParams() {
public Component getComponent() {
找到了。doStartTag()方法第1句,调用getBean(),其中有个参数调用了getStack(),实际上这个方法返回的就是我上面说的ValueStack。F5进入:
public class StrutsBodyTagSupport extends BodyTagSupport {
private static final long serialVersionUID = -4226175L;
protected ValueStack getStack() {
return TagUtils.getStack(pageContext);
该方法是在ComponentTagSupport的父类StrutsBodyTagSupport中。其中只有一句TagUtils.getStack(pageContext),pageContext就是servlet的页面上下文内置对象,F5进入TagUtils.getStack(pageContext):
public static ValueStack getStack(PageContext pageContext) {
HttpServletRequest req = (HttpServletRequest) pageContext.getRequest();
ValueStack stack = (ValueStack) req.getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY);
if (stack == null) {
HttpServletResponse res = (HttpServletResponse) pageContext.getResponse();
Dispatcher du = Dispatcher.getInstance();
if (du == null) {
throw new ConfigurationException("The Struts dispatcher cannot be found.
This is usually caused by "+
"using Struts tags without the associated filter. Struts tags are only usable when the request "+
"has passed through its servlet filter, which initializes the Struts dispatcher needed for this tag.");
stack = du.getContainer().getInstance(ValueStackFactory.class).createValueStack();
Map&String, Object& extraContext = du.createContextMap(new RequestMap(req),
req.getParameterMap(),
new SessionMap(req),
new ApplicationMap(pageContext.getServletContext()),
pageContext.getServletContext());
extraContext.put(ServletActionContext.PAGE_CONTEXT, pageContext);
stack.getContext().putAll(extraContext);
req.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, stack);
// also tie this stack/context to the ThreadLocal
ActionContext.setContext(new ActionContext(stack.getContext()));
// let's make sure that the current page context is in the action context
Map&String, Object& context = stack.getContext();
context.put(ServletActionContext.PAGE_CONTEXT, pageContext);
AttributeMap attrMap = new AttributeMap(context);
context.put("attr", attrMap);
方法第1句,通过页面上下文对象pageContext获得本次请求的request对象,第2句在通过req.getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY)获得ValueStack,因为事先struts2已经通过request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, valuesStack)将ValueStack存于request的ServletActionContext.STRUTS_VALUESTACK_KEY属性中,所以通过第2句就可以获得ValueStack,直接return stack返回到ComponentTagSupport类的doStartTag()方法,如下(我在把代码粘下):
public int doStartTag() throws JspException {
component = getBean(getStack(), (HttpServletRequest) pageContext.getRequest(), (HttpServletResponse) pageContext.getResponse());
Container container = Dispatcher.getInstance().getContainer();
container.inject(component);
populateParams();
boolean evalBody = component.start(pageContext.getOut());
if (evalBody) {
return component.usesBody() ? EVAL_BODY_BUFFERED : EVAL_BODY_INCLUDE;
return SKIP_BODY;
执行完getStack()接着看getBean()方法,在ComponentTagSupport类中可以找到,getBean()方法被定义为抽象方法,所以具体的实现要在其子类PropertyTag中找,F5进入:
public Component getBean(ValueStack stack, HttpServletRequest req, HttpServletResponse res) {
return new Property(stack);
方法只有一句通过new 生成了Property实例,同时将stack作为构造参数传进去,这个stack就是我们上面通过getStack()得到的ValueStack,执行完后程序会重新回到ComponentTagSupport类的doStartTag()方法,我把代码在粘下:
public int doStartTag() throws JspException {
component = getBean(getStack(), (HttpServletRequest) pageContext.getRequest(), (HttpServletResponse) pageContext.getResponse());
Container container = Dispatcher.getInstance().getContainer();
container.inject(component);
populateParams();
boolean evalBody = component.start(pageContext.getOut());
if (evalBody) {
return component.usesBody() ? EVAL_BODY_BUFFERED : EVAL_BODY_INCLUDE;
return SKIP_BODY;
这样component中实际引用的就是Property实例,第2、3句,调用容器,通过container.inject(component)将Property中需要注入的属性赋值(带有@Inject标注的)。populateParams()句将标签属性添加到component相应属性中,如value、escape。核心在下面这句component.start(pageContext.getOut()),通过ognl访问ValueStack从而获得标签的value值,F5进入Property的start():
public boolean start(Writer writer) {
boolean result = super.start(writer);
String actualValue =
if (value == null) {
value = "top";
value = stripExpressionIfAltSyntax(value);
// exception: don't call findString(), since we don't want the
expression parsed in this one case. it really
doesn't make sense, in fact.
actualValue = (String) getStack().findValue(value, String.class);
if (actualValue != null) {
writer.write(prepare(actualValue));
} else if (defaultValue != null) {
writer.write(prepare(defaultValue));
} catch (IOException e) {
("Could not print out value '" + value + "'", e);
直接看(String) getStack().findValue(value, String.class) &调用getStack()获得ValueStack,这个ValueStack实在Property实例生成时通过构造方法传入的。之后调用ValueStack的findValue()方法, 其中参数value就是&s:property value=""/&标签的value属性值。我们在上面说过ValueStack的实现类默认使用的是com.opensymphony.xwork2.ognl.OgnlValueStack类,F5进入其findValue():
public Object findValue(String expr, Class asType) {
if (expr == null) {
if ((overrides != null) && overrides.containsKey(expr)) {
expr = (String) overrides.get(expr);
Object value = ognlUtil.getValue(expr, context, root, asType);
if (value != null) {
return findInContext(expr);
} catch (OgnlException e) {
return findInContext(expr);
} catch (Exception e) {
logLookupFailure(expr, e);
return findInContext(expr);
} finally {
ReflectionContextState.clear(context);
直接看ognlUtil.getValue(expr, context, root, asType)句,可以看到content、root就是我们上面说的ValueStack中getContext()和getRoot()方法中对应的属性值,我们说过它分别对应ognl中的上下文和根对象。ognlUtil是com.opensymphony.xwork2.ognl.OgnlUtil类的实例,是struts2中用于操作ognl而单独封装的管理类, F5进入ognlUtil.getValue()方法:
public Object getValue(String name, Map&String, Object& context, Object root, Class resultType) throws OgnlException {
return Ognl.getValue(compile(name), context, root, resultType);
实际上,上面的方法只是将name做处理后直接调用ognl的getValue()方法。context作为ognl的上下文,root作为ognl的根对象,name是属性名。此时的root中就存放着当前action的实例。return返回的值就是&s:property value=""/&标签最终所获得的值。说道这熟悉ognl的应该已经明白了。

我要回帖

更多关于 struts2 请求 的文章

 

随机推荐