转: http://blog.youkuaiyun.com/accpsz/archive/2010/12/31/6108917.aspx
//
this is needed because the result will be executed, then control will return to the Interceptor, which will
// return above and flow through again
if ( ! executed) {
// 在Result返回之前调用preResultListeners
if (preResultListeners != null ) {
for (Iterator iterator = preResultListeners.iterator();
iterator.hasNext();) {
PreResultListener listener = (PreResultListener) iterator.next();
String _profileKey = " preResultListener: " ;
try {
UtilTimerStack.push(_profileKey);
listener.beforeResult( this , resultCode);
}
finally {
UtilTimerStack.pop(_profileKey);
}
}
}
// now execute the result, if we're supposed to
if (proxy.getExecuteResult()) {
executeResult();
}
executed = true ;
}
return resultCode;
}
finally {
UtilTimerStack.pop(profileKey);
}
}
// return above and flow through again
if ( ! executed) {
// 在Result返回之前调用preResultListeners
if (preResultListeners != null ) {
for (Iterator iterator = preResultListeners.iterator();
iterator.hasNext();) {
PreResultListener listener = (PreResultListener) iterator.next();
String _profileKey = " preResultListener: " ;
try {
UtilTimerStack.push(_profileKey);
listener.beforeResult( this , resultCode);
}
finally {
UtilTimerStack.pop(_profileKey);
}
}
}
// now execute the result, if we're supposed to
if (proxy.getExecuteResult()) {
executeResult();
}
executed = true ;
}
return resultCode;
}
finally {
UtilTimerStack.pop(profileKey);
}
}
看程序中的if(interceptors.hasNext())语句,当然,interceptors里存储的是interceptorMapping列表(它包括一个Interceptor和一个name),所有的截拦器必须实现Interceptor的intercept方法,而该方法的参数恰恰又是ActionInvocation,在intercept方法中还是调用invocation.invoke(),从而实现了一个Interceptor链的调用。当所有的Interceptor执行完,最后调用invokeActionOnly方法来执行Action相应的方法。
protected
String invokeAction(Object action, ActionConfig actionConfig)
throws
Exception {
String methodName = proxy.getMethod();
String timerKey = " invokeAction: " + proxy.getActionName();
try {
UtilTimerStack.push(timerKey);
boolean methodCalled = false ;
Object methodResult = null ;
Method method = null ;
try {
// 获得需要执行的方法
method = getAction().getClass().getMethod(methodName, new Class[ 0 ]);
} catch (NoSuchMethodException e) {
// 如果没有对应的方法,则使用do+Xxxx来再次获得方法
try {
String altMethodName = " do " + methodName.substring( 0 , 1 ).toUpperCase() + methodName.substring( 1 );
method = getAction().getClass().getMethod(altMethodName, new Class[ 0 ]);
} catch (NoSuchMethodException e1) {
// well, give the unknown handler a shot
if (unknownHandler != null ) {
try {
methodResult = unknownHandler.handleUnknownActionMethod(action, methodName);
methodCalled = true ;
} catch (NoSuchMethodException e2) {
// throw the original one
throw e;
}
} else {
throw e;
}
}
}
if ( ! methodCalled) {
methodResult = method.invoke(action, new Object[ 0 ]);
}
// 根据不同的Result类型返回不同值
// 如输出流Result
if (methodResult instanceof Result) {
this .explicitResult = (Result) methodResult;
return null ;
} else {
return (String) methodResult;
}
} catch (NoSuchMethodException e) {
throw new IllegalArgumentException( " The " + methodName + " () is not defined in action " + getAction().getClass() + "" );
} catch (InvocationTargetException e) {
// We try to return the source exception.
Throwable t = e.getTargetException();
if (actionEventListener != null ) {
String result = actionEventListener.handleException(t, getStack());
if (result != null ) {
return result;
}
}
if (t instanceof Exception) {
throw (Exception) t;
} else {
throw e;
}
} finally {
UtilTimerStack.pop(timerKey);
}
}
String methodName = proxy.getMethod();
String timerKey = " invokeAction: " + proxy.getActionName();
try {
UtilTimerStack.push(timerKey);
boolean methodCalled = false ;
Object methodResult = null ;
Method method = null ;
try {
// 获得需要执行的方法
method = getAction().getClass().getMethod(methodName, new Class[ 0 ]);
} catch (NoSuchMethodException e) {
// 如果没有对应的方法,则使用do+Xxxx来再次获得方法
try {
String altMethodName = " do " + methodName.substring( 0 , 1 ).toUpperCase() + methodName.substring( 1 );
method = getAction().getClass().getMethod(altMethodName, new Class[ 0 ]);
} catch (NoSuchMethodException e1) {
// well, give the unknown handler a shot
if (unknownHandler != null ) {
try {
methodResult = unknownHandler.handleUnknownActionMethod(action, methodName);
methodCalled = true ;
} catch (NoSuchMethodException e2) {
// throw the original one
throw e;
}
} else {
throw e;
}
}
}
if ( ! methodCalled) {
methodResult = method.invoke(action, new Object[ 0 ]);
}
// 根据不同的Result类型返回不同值
// 如输出流Result
if (methodResult instanceof Result) {
this .explicitResult = (Result) methodResult;
return null ;
} else {
return (String) methodResult;
}
} catch (NoSuchMethodException e) {
throw new IllegalArgumentException( " The " + methodName + " () is not defined in action " + getAction().getClass() + "" );
} catch (InvocationTargetException e) {
// We try to return the source exception.
Throwable t = e.getTargetException();
if (actionEventListener != null ) {
String result = actionEventListener.handleException(t, getStack());
if (result != null ) {
return result;
}
}
if (t instanceof Exception) {
throw (Exception) t;
} else {
throw e;
}
} finally {
UtilTimerStack.pop(timerKey);
}
}
好了,action执行完了,还要根据ResultConfig返回到view,也就是在invoke方法中调用executeResult方法。
private
void
executeResult()
throws
Exception {
// 根据ResultConfig创建Result
result = createResult();
String timerKey = " executeResult: " + getResultCode();
try {
UtilTimerStack.push(timerKey);
if (result != null ) {
// 这儿正式执行:)
// 可以参考Result的实现,如用了比较多的ServletDispatcherResult,ServletActionRedirectResult,ServletRedirectResult
result.execute( this );
} else if (resultCode != null && ! Action.NONE.equals(resultCode)) {
throw new ConfigurationException( " No result defined for action " + getAction().getClass().getName()
+ " and result " + getResultCode(), proxy.getConfig());
} else {
if (LOG.isDebugEnabled()) {
LOG.debug( " No result returned for action " + getAction().getClass().getName() + " at " + proxy.getConfig().getLocation());
}
}
} finally {
UtilTimerStack.pop(timerKey);
}
}
public Result createResult() throws Exception {
if (explicitResult != null ) {
Result ret = explicitResult;
explicitResult = null ;;
return ret;
}
ActionConfig config = proxy.getConfig();
Map results = config.getResults();
ResultConfig resultConfig = null ;
synchronized (config) {
try {
// 根据result名称获得ResultConfig,resultCode就是result的name
resultConfig = (ResultConfig) results.get(resultCode);
} catch (NullPointerException e) {
}
if (resultConfig == null ) {
// 如果找不到对应name的ResultConfig,则使用name为*的Result
resultConfig = (ResultConfig) results.get( " * " );
}
}
if (resultConfig != null ) {
try {
// 参照StrutsObjectFactory的代码
Result result = objectFactory.buildResult(resultConfig, invocationContext.getContextMap());
return result;
} catch (Exception e) {
LOG.error( " There was an exception while instantiating the result of type " + resultConfig.getClassName(), e);
throw new XWorkException(e, resultConfig);
}
} else if (resultCode != null && ! Action.NONE.equals(resultCode) && unknownHandler != null ) {
return unknownHandler.handleUnknownResult(invocationContext, proxy.getActionName(), proxy.getConfig(), resultCode);
}
return null ;
}
// StrutsObjectFactory
public Result buildResult(ResultConfig resultConfig, Map extraContext) throws Exception {
String resultClassName = resultConfig.getClassName();
if (resultClassName == null )
return null ;
// 创建Result,因为Result是有状态的,所以每次请求都新建一个
Object result = buildBean(resultClassName, extraContext);
// 这句很重要,后面将会谈到,reflectionProvider参见OgnlReflectionProvider;
// resultConfig.getParams()就是result配置文件里所配置的参数<param>
</param>
// setProperties方法最终调用的是Ognl类的setValue方法
// 这句其实就是把param名值设置到根对象result上
reflectionProvider.setProperties(resultConfig.getParams(), result, extraContext);
if (result instanceof Result)
return (Result) result;
throw new ConfigurationException(result.getClass().getName() + " does not implement Result. " );
}
// 根据ResultConfig创建Result
result = createResult();
String timerKey = " executeResult: " + getResultCode();
try {
UtilTimerStack.push(timerKey);
if (result != null ) {
// 这儿正式执行:)
// 可以参考Result的实现,如用了比较多的ServletDispatcherResult,ServletActionRedirectResult,ServletRedirectResult
result.execute( this );
} else if (resultCode != null && ! Action.NONE.equals(resultCode)) {
throw new ConfigurationException( " No result defined for action " + getAction().getClass().getName()
+ " and result " + getResultCode(), proxy.getConfig());
} else {
if (LOG.isDebugEnabled()) {
LOG.debug( " No result returned for action " + getAction().getClass().getName() + " at " + proxy.getConfig().getLocation());
}
}
} finally {
UtilTimerStack.pop(timerKey);
}
}
public Result createResult() throws Exception {
if (explicitResult != null ) {
Result ret = explicitResult;
explicitResult = null ;;
return ret;
}
ActionConfig config = proxy.getConfig();
Map results = config.getResults();
ResultConfig resultConfig = null ;
synchronized (config) {
try {
// 根据result名称获得ResultConfig,resultCode就是result的name
resultConfig = (ResultConfig) results.get(resultCode);
} catch (NullPointerException e) {
}
if (resultConfig == null ) {
// 如果找不到对应name的ResultConfig,则使用name为*的Result
resultConfig = (ResultConfig) results.get( " * " );
}
}
if (resultConfig != null ) {
try {
// 参照StrutsObjectFactory的代码
Result result = objectFactory.buildResult(resultConfig, invocationContext.getContextMap());
return result;
} catch (Exception e) {
LOG.error( " There was an exception while instantiating the result of type " + resultConfig.getClassName(), e);
throw new XWorkException(e, resultConfig);
}
} else if (resultCode != null && ! Action.NONE.equals(resultCode) && unknownHandler != null ) {
return unknownHandler.handleUnknownResult(invocationContext, proxy.getActionName(), proxy.getConfig(), resultCode);
}
return null ;
}
// StrutsObjectFactory
public Result buildResult(ResultConfig resultConfig, Map extraContext) throws Exception {
String resultClassName = resultConfig.getClassName();
if (resultClassName == null )
return null ;
// 创建Result,因为Result是有状态的,所以每次请求都新建一个
Object result = buildBean(resultClassName, extraContext);
// 这句很重要,后面将会谈到,reflectionProvider参见OgnlReflectionProvider;
// resultConfig.getParams()就是result配置文件里所配置的参数<param>

// setProperties方法最终调用的是Ognl类的setValue方法
// 这句其实就是把param名值设置到根对象result上
reflectionProvider.setProperties(resultConfig.getParams(), result, extraContext);
if (result instanceof Result)
return (Result) result;
throw new ConfigurationException(result.getClass().getName() + " does not implement Result. " );
}
最后补充一下,Struts2的查找值和设置值都是使用Ognl来实现的。关于Ognl的介绍可以到其官方网站查看http://www.ognl.org/,我在网上也找到另外一篇http://www.iteye.com/topic/254684和http://www.iteye.com/topic/223612。完了来看下面这段小测试程序(其它的Ognl的测试可以自己添加)。
public
class
TestOgnl {
private User user;
private Map context;
@Before
public void setUp() throws Exception {
}
@Test
public void ognlGetValue() throws Exception {
reset();
Assert.assertEquals( " myyate " , Ognl.getValue( " name " , user));
Assert.assertEquals( " cares " , Ognl.getValue( " dept.name " , user));
Assert.assertEquals( " myyate " , Ognl.getValue( " name " , context, user));
Assert.assertEquals( " contextmap " , Ognl.getValue( " #name " , context, user));
Assert.assertEquals( " parker " , Ognl.getValue( " #pen " , context, user));
}
@Test
public void ognlSetValue() throws Exception {
reset();
Ognl.setValue( " name " , user, " myyateC " );
Assert.assertEquals( " myyateC " , Ognl.getValue( " name " , user));
Ognl.setValue( " dept.name " , user, " caresC " );
Assert.assertEquals( " caresC " , Ognl.getValue( " dept.name " , user));
Assert.assertEquals( " contextmap " , Ognl.getValue( " #name " , context, user));
Ognl.setValue( " #name " , context, user, " contextmapC " );
Assert.assertEquals( " contextmapC " , Ognl.getValue( " #name " , context, user));
Assert.assertEquals( " parker " , Ognl.getValue( " #pen " , context, user));
Ognl.setValue( " #name " , context, user, " parkerC " );
Assert.assertEquals( " parkerC " , Ognl.getValue( " #name " , context, user));
}
public static void main(String[] args) throws Exception {
JUnitCore.runClasses(TestOgnl. class );
}
private void reset() {
user = new User( " myyate " , new Dept( " cares " ));
context = new OgnlContext();
context.put( " pen " , " parker " );
context.put( " name " , " contextmap " );
}
}
class User {
public User(String name, Dept dept) {
this .name = name;
this .dept = dept;
}
String name;
private Dept dept;
public Dept getDept() {
return dept;
}
public String getName() {
return name;
}
public void setDept(Dept dept) {
this .dept = dept;
}
public void setName(String name) {
this .name = name;
}
}
class Dept {
public Dept(String name) {
this .name = name;
}
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this .name = name;
}
}
private User user;
private Map context;
@Before
public void setUp() throws Exception {
}
@Test
public void ognlGetValue() throws Exception {
reset();
Assert.assertEquals( " myyate " , Ognl.getValue( " name " , user));
Assert.assertEquals( " cares " , Ognl.getValue( " dept.name " , user));
Assert.assertEquals( " myyate " , Ognl.getValue( " name " , context, user));
Assert.assertEquals( " contextmap " , Ognl.getValue( " #name " , context, user));
Assert.assertEquals( " parker " , Ognl.getValue( " #pen " , context, user));
}
@Test
public void ognlSetValue() throws Exception {
reset();
Ognl.setValue( " name " , user, " myyateC " );
Assert.assertEquals( " myyateC " , Ognl.getValue( " name " , user));
Ognl.setValue( " dept.name " , user, " caresC " );
Assert.assertEquals( " caresC " , Ognl.getValue( " dept.name " , user));
Assert.assertEquals( " contextmap " , Ognl.getValue( " #name " , context, user));
Ognl.setValue( " #name " , context, user, " contextmapC " );
Assert.assertEquals( " contextmapC " , Ognl.getValue( " #name " , context, user));
Assert.assertEquals( " parker " , Ognl.getValue( " #pen " , context, user));
Ognl.setValue( " #name " , context, user, " parkerC " );
Assert.assertEquals( " parkerC " , Ognl.getValue( " #name " , context, user));
}
public static void main(String[] args) throws Exception {
JUnitCore.runClasses(TestOgnl. class );
}
private void reset() {
user = new User( " myyate " , new Dept( " cares " ));
context = new OgnlContext();
context.put( " pen " , " parker " );
context.put( " name " , " contextmap " );
}
}
class User {
public User(String name, Dept dept) {
this .name = name;
this .dept = dept;
}
String name;
private Dept dept;
public Dept getDept() {
return dept;
}
public String getName() {
return name;
}
public void setDept(Dept dept) {
this .dept = dept;
}
public void setName(String name) {
this .name = name;
}
}
class Dept {
public Dept(String name) {
this .name = name;
}
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this .name = name;
}
}
这样,一个Struts2的请求流程基本上就结束了。其实我觉得做项目把Struts2参考文档看两遍就可以了,