深入分析struts2的ognl表达式。前面的2篇文章已经详细的分析了ognl获取数据的过程和设置数据的过程。其中最重要的点是ognl的三要素:
(1)表达式(Expression)表达式是整个OGNL的核心,所有的OGNL操作都是针对表达式的解析后进行的。简介的概括“干什么”
(2)根对象(Root Object) 根对象可以理解为OGNL的操作对象。简介的概括“对谁干”或者“对谁操作”
(3)上下文环境(Context) OGNL的内部,所有的操作都会在一个特定的环境中运行,简介的概括“在哪干”或者“在哪操作”
如果明白了ognl的三要素,下面就好理解了。
《刨根问底-struts-serviceAction()创建并执行action》中分析了执行action方法之前,循环执行拦截器,其中ParametersInterceptor拦截器主要工作:把jsp中传来的数值赋值到action类中的属性。现在就看看ParametersInterceptor类doIntercept()方法
1、ParametersInterceptor类doIntercept()代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
@Override public String doIntercept(ActionInvocation invocation) throws Exception { Object action = invocation.getAction(); if (!(action instanceof NoParameters)) { ActionContext ac = invocation.getInvocationContext(); final Map<String, Object> parameters = retrieveParameters(ac); if (LOG.isDebugEnabled()) { LOG.debug( "Setting params " + getParameterLogMap(parameters)); } if (parameters != null ) { Map<String, Object> contextMap = ac.getContextMap(); try { ReflectionContextState.setCreatingNullObjects(contextMap, true ); ReflectionContextState.setDenyMethodExecution(contextMap, true ); ReflectionContextState.setReportingConversionErrors(contextMap, true ); ValueStack stack = ac.getValueStack(); setParameters(action, stack, parameters); } finally { ReflectionContextState.setCreatingNullObjects(contextMap, false ); ReflectionContextState.setDenyMethodExecution(contextMap, false ); ReflectionContextState.setReportingConversionErrors(contextMap, false ); } } } return invocation.invoke(); } |
注释:(1)Object action = invocation.getAction(),获取action对象,在这里就是Login,其中属性userName和passwod都为空。
(2)判断action是否属于NoParameters接口,如果是什么不处理
(3)ActionContext ac = invocation.getInvocationContext(),获取上下文对象ActionContext ,作为struts2执行Action时的上下文,存储了action在执行时需要用到的对象。如我们需要关注的ServletContext,Session, HttpServletRequest ,parameters等。
ActionContext类中有Map context全局变量,把所有的数据都保存到其中。
现在贴出context中的值:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
|
{com.opensymphony.xwork2.dispatcher.HttpServletRequest=org.apache.struts2.dispatcher.StrutsRequestWrapper @e9c592 , application={org.apache.catalina.resources=org.apache.naming.resources.ProxyDirContext @187b5ff , org.apache.AnnotationProcessor=org.apache.catalina.util.DefaultAnnotationProcessor @bdb6ae , org.apache.catalina.jsp_classpath=/E:/javahome/workspace/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/wtpwebapps/strutsDemo/WEB-INF/classes/; /E:/javahome/workspace/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/wtpwebapps/strutsDemo/WEB-INF/lib/activemq-all- 5.6 . 0 .jar; /E:/javahome/workspace/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/wtpwebapps/strutsDemo/WEB-INF/lib/commons-beanutils- 1.7 . 0 .jar; /E:/javahome/workspace/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/wtpwebapps/strutsDemo/WEB-INF/lib/commons-dbutils- 1.3 .jar; /E:/javahome/workspace/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/wtpwebapps/strutsDemo/WEB-INF/lib/commons-io- 1.4 .jar; /E:/javahome/workspace/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/wtpwebapps/strutsDemo/WEB-INF/lib/commons-lang- 2.1 .jar; /E:/javahome/workspace/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/wtpwebapps/strutsDemo/WEB-INF/lib/commons-logging- 1.0 . 4 .jar; /E:/javahome/workspace/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/wtpwebapps/strutsDemo/WEB-INF/lib/freemarker- 2.3 . 9 .jar; /E:/javahome/workspace/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/wtpwebapps/strutsDemo/WEB-INF/lib/log4j_128.jar; /E:/javahome/workspace/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/wtpwebapps/strutsDemo/WEB-INF/lib/mysql-connector-java- 5.1 . 9 -bin.jar; /E:/javahome/workspace/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/wtpwebapps/strutsDemo/WEB-INF/lib/ognl- 2.6 . 11 .jar; /E:/javahome/workspace/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/wtpwebapps/strutsDemo/WEB-INF/lib/struts2-core- 2.0 . 14 .jar; /E:/javahome/workspace/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/wtpwebapps/strutsDemo/WEB-INF/lib/xwork- 2.0 . 7 .jar; /E:/javahome/apache-tomcat- 6.0 . 29 /lib/; /E:/javahome/apache-tomcat- 6.0 . 29 /lib/annotations-api.jar; /E:/javahome/apache-tomcat- 6.0 . 29 /lib/catalina-ant.jar; /E:/javahome/apache-tomcat- 6.0 . 29 /lib/catalina-ha.jar; /E:/javahome/apache-tomcat- 6.0 . 29 /lib/catalina-tribes.jar; /E:/javahome/apache-tomcat- 6.0 . 29 /lib/catalina.jar; /E:/javahome/apache-tomcat- 6.0 . 29 /lib/el-api.jar; /E:/javahome/apache-tomcat- 6.0 . 29 /lib/jasper-el.jar; /E:/javahome/apache-tomcat- 6.0 . 29 /lib/jasper-jdt.jar; /E:/javahome/apache-tomcat- 6.0 . 29 /lib/jasper.jar; /E:/javahome/apache-tomcat- 6.0 . 29 /lib/jsp-api.jar; /E:/javahome/apache-tomcat- 6.0 . 29 /lib/servlet-api.jar; /E:/javahome/apache-tomcat- 6.0 . 29 /lib/tomcat-coyote.jar; /E:/javahome/apache-tomcat- 6.0 . 29 /lib/tomcat-dbcp.jar; /E:/javahome/apache-tomcat- 6.0 . 29 /lib/tomcat-i18n-es.jar; /E:/javahome/apache-tomcat- 6.0 . 29 /lib/tomcat-i18n-fr.jar; /E:/javahome/apache-tomcat- 6.0 . 29 /lib/tomcat-i18n-ja.jar; /E:/javahome/apache-tomcat- 6.0 . 29 /bin/bootstrap.jar; /E:/javahome/jdk/lib/tools.jar; /E:/javahome/jdk/jre/lib/ext/dnsns.jar; /E:/javahome/jdk/jre/lib/ext/localedata.jar; /E:/javahome/jdk/jre/lib/ext/sunjce_provider.jar; /E:/javahome/jdk/jre/lib/ext/sunmscapi.jar; /E:/javahome/jdk/jre/lib/ext/sunpkcs11.jar, org.apache.jasper.runtime.JspApplicationContextImpl=org.apache.jasper.runtime.JspApplicationContextImpl @f97d27 , org.apache.catalina.WELCOME_FILES=[Ljava.lang.String; @17b6074 , javax.servlet.context.tempdir=E:\javahome\workspace\.metadata\.plugins\org.eclipse.wst.server.core\tmp0\work\Catalina\localhost\strutsDemo}, com.opensymphony.xwork2.ActionContext.locale=zh_CN, com.opensymphony.xwork2.dispatcher.HttpServletResponse=org.apache.catalina.connector.ResponseFacade @12478a9 , com.opensymphony.xwork2.ActionContext.name=doLogin, current.property.path= null , com.opensymphony.xwork2.ActionContext.application={ org.apache.catalina.resources=org.apache.naming.resources.ProxyDirContext @187b5ff , org.apache.AnnotationProcessor=org.apache.catalina.util.DefaultAnnotationProcessor @bdb6ae , org.apache.catalina.jsp_classpath=/E:/javahome/workspace/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/wtpwebapps/strutsDemo/WEB-INF/classes/; /E:/javahome/workspace/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/wtpwebapps/strutsDemo/WEB-INF/lib/activemq-all- 5.6 . 0 .jar; /E:/javahome/workspace/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/wtpwebapps/strutsDemo/WEB-INF/lib/commons-beanutils- 1.7 . 0 .jar; /E:/javahome/workspace/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/wtpwebapps/strutsDemo/WEB-INF/lib/commons-dbutils- 1.3 .jar; /E:/javahome/workspace/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/wtpwebapps/strutsDemo/WEB-INF/lib/commons-io- 1.4 .jar; /E:/javahome/workspace/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/wtpwebapps/strutsDemo/WEB-INF/lib/commons-lang- 2.1 .jar; /E:/javahome/workspace/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/wtpwebapps/strutsDemo/WEB-INF/lib/commons-logging- 1.0 . 4 .jar; /E:/javahome/workspace/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/wtpwebapps/strutsDemo/WEB-INF/lib/freemarker- 2.3 . 9 .jar; /E:/javahome/workspace/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/wtpwebapps/strutsDemo/WEB-INF/lib/log4j_128.jar; /E:/javahome/workspace/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/wtpwebapps/strutsDemo/WEB-INF/lib/mysql-connector-java- 5.1 . 9 -bin.jar; /E:/javahome/workspace/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/wtpwebapps/strutsDemo/WEB-INF/lib/ognl- 2.6 . 11 .jar; /E:/javahome/workspace/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/wtpwebapps/strutsDemo/WEB-INF/lib/struts2-core- 2.0 . 14 .jar; /E:/javahome/workspace/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/wtpwebapps/strutsDemo/WEB-INF/lib/xwork- 2.0 . 7 .jar; /E:/javahome/apache-tomcat- 6.0 . 29 /lib/;/E:/javahome/apache-tomcat- 6.0 . 29 /lib/annotations-api.jar; /E:/javahome/apache-tomcat- 6.0 . 29 /lib/catalina-ant.jar;/E:/javahome/apache-tomcat- 6.0 . 29 /lib/catalina-ha.jar; /E:/javahome/apache-tomcat- 6.0 . 29 /lib/catalina-tribes.jar;/E:/javahome/apache-tomcat- 6.0 . 29 /lib/catalina.jar; /E:/javahome/apache-tomcat- 6.0 . 29 /lib/el-api.jar;/E:/javahome/apache-tomcat- 6.0 . 29 /lib/jasper-el.jar; /E:/javahome/apache-tomcat- 6.0 . 29 /lib/jasper-jdt.jar;/E:/javahome/apache-tomcat- 6.0 . 29 /lib/jasper.jar; /E:/javahome/apache-tomcat- 6.0 . 29 /lib/jsp-api.jar; /E:/javahome/apache-tomcat- 6.0 . 29 /lib/servlet-api.jar; /E:/javahome/apache-tomcat- 6.0 . 29 /lib/tomcat-coyote.jar; /E:/javahome/apache-tomcat- 6.0 . 29 /lib/tomcat-dbcp.jar; /E:/javahome/apache-tomcat- 6.0 . 29 /lib/tomcat-i18n-es.jar; /E:/javahome/apache-tomcat- 6.0 . 29 /lib/tomcat-i18n-fr.jar; /E:/javahome/apache-tomcat- 6.0 . 29 /lib/tomcat-i18n-ja.jar; /E:/javahome/apache-tomcat- 6.0 . 29 /bin/bootstrap.jar; /E:/javahome/jdk/lib/tools.jar; /E:/javahome/jdk/jre/lib/ext/dnsns.jar; /E:/javahome/jdk/jre/lib/ext/localedata.jar; /E:/javahome/jdk/jre/lib/ext/sunjce_provider.jar; /E:/javahome/jdk/jre/lib/ext/sunmscapi.jar; /E:/javahome/jdk/jre/lib/ext/sunpkcs11.jar, org.apache.jasper.runtime.JspApplicationContextImpl=org.apache.jasper.runtime.JspApplicationContextImpl @f97d27 , org.apache.catalina.WELCOME_FILES=[Ljava.lang.String; @17b6074 , javax.servlet.context.tempdir=E:\javahome\workspace\.metadata\.plugins\org.eclipse.wst.server.core\tmp0\work\Catalina\localhost\strutsDemo}, last.property.accessed= null , attr=org.apache.struts2.util.AttributeMap @16dc5c9 , com.opensymphony.xwork2.dispatcher.ServletContext=org.apache.catalina.core.ApplicationContextFacade @1d433c1 , com.opensymphony.xwork2.ActionContext.session={}, com.opensymphony.xwork2.ActionContext.actionInvocation=com.opensymphony.xwork2.DefaultActionInvocation @92015d , session={}, com.opensymphony.xwork2.util.ValueStack.ValueStack=com.opensymphony.xwork2.util.OgnlValueStack @197871d , last.bean.accessed= null , request={struts.valueStack=com.opensymphony.xwork2.util.OgnlValueStack @197871d }, struts.actionMapping=org.apache.struts2.dispatcher.mapper.ActionMapping @898587 , parameters={userName=[Ljava.lang.String; @9d9edd , password=[Ljava.lang.String; @28df48 }, com.opensymphony.xwork2.ActionContext.parameters={userName=[Ljava.lang.String; @9d9edd , password=[Ljava.lang.String; @28df48 }} |
上面的代码比较多,可以中重点看几个:
com.opensymphony.xwork2.dispatcher.HttpServletRequest=org.apache.struts2.dispatcher.StrutsRequestWrapper@e9c592
com.opensymphony.xwork2.dispatcher.HttpServletResponse=org.apache.catalina.connector.ResponseFacade@12478a9
com.opensymphony.xwork2.ActionContext.name=doLogin
com.opensymphony.xwork2.dispatcher.ServletContext=org.apache.catalina.core.ApplicationContextFacade@1d433c1,
com.opensymphony.xwork2.util.ValueStack.ValueStack=com.opensymphony.xwork2.util.OgnlValueStack@197871d,
parameters={userName=[Ljava.lang.String;@9d9edd, password=[Ljava.lang.String;@28df48},
这都是常用到的几个对象,尤其是parameters,其中保存了userName和password值
(4)Map parameters = ac.getParameters(),在ac对象的context中获取parameters 。
(5)Map contextMap = ac.getContextMap(),获取ac对象的context,在这是ognl.OgnlContext,如果这里为什么可以是OgnlContext有疑问,请看前面的几篇文章。简单的说一句OgnlContext 实现map接口。
(6) ValueStack stack = ac.getValueStack(),获得ValueStack ,这里是com.opensymphony.xwork2.util.OgnlValueStack
(7)setParameters设置参数
2、setParameters()代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
|
protected void setParameters(Object action, ValueStack stack, final Map<String, Object> parameters) { ParameterNameAware parameterNameAware = (action instanceof ParameterNameAware) ? (ParameterNameAware) action : null ; Map<String, Object> params; Map<String, Object> acceptableParameters; if (ordered) { params = new TreeMap<String, Object>(getOrderedComparator()); acceptableParameters = new TreeMap<String, Object>(getOrderedComparator()); params.putAll(parameters); } else { params = new TreeMap<String, Object>(parameters); acceptableParameters = new TreeMap<String, Object>(); } for (Map.Entry<String, Object> entry : params.entrySet()) { String name = entry.getKey(); boolean acceptableName = acceptableName(name) && (parameterNameAware == null || parameterNameAware.acceptableParameterName(name)); if (acceptableName) { acceptableParameters.put(name, entry.getValue()); } } ValueStack newStack = valueStackFactory.createValueStack(stack); boolean clearableStack = newStack instanceof ClearableValueStack; if (clearableStack) { //if the stack's context can be cleared, do that to prevent OGNL //from having access to objects in the stack, see XW-641 ((ClearableValueStack)newStack).clearContextValues(); Map<String, Object> context = newStack.getContext(); ReflectionContextState.setCreatingNullObjects(context, true ); ReflectionContextState.setDenyMethodExecution(context, true ); ReflectionContextState.setReportingConversionErrors(context, true ); } boolean memberAccessStack = newStack instanceof MemberAccessValueStack; if (memberAccessStack) { //block or allow access to properties //see WW-2761 for more details MemberAccessValueStack accessValueStack = (MemberAccessValueStack) newStack; accessValueStack.setAcceptProperties(acceptParams); accessValueStack.setExcludeProperties(excludeParams); } for (Map.Entry<String, Object> entry : acceptableParameters.entrySet()) { String name = entry.getKey(); Object value = entry.getValue(); try { newStack.setValue(name, value); } catch (RuntimeException e) { if (devMode) { String developerNotification = LocalizedTextUtil.findText(ParametersInterceptor. class , "devmode.notification" , ActionContext.getContext().getLocale(), "Developer Notification:\n{0}" , new Object[]{ "Unexpected Exception caught setting '" + name + "' on '" + action.getClass() + ": " + e.getMessage() }); LOG.error(developerNotification); if (action instanceof ValidationAware) { ((ValidationAware) action).addActionMessage(developerNotification); } } } } if (clearableStack && (stack.getContext() != null ) && (newStack.getContext() != null )) stack.getContext().put(ActionContext.CONVERSION_ERRORS, newStack.getContext().get(ActionContext.CONVERSION_ERRORS)); addParametersToContext(ActionContext.getContext(), acceptableParameters); } |
注释:(1)判断action是否实现ParameterNameAware接口,如果没有创建TreeMap,并且赋值给params
(2)ValueStack newStack = ValueStackFactory.getFactory().createValueStack(stack),获得一个valueStack。 ValueStackFactory.getFactory()获得是OgnlValueStackFactory。
(3)前面代码略过,请看重要的一行 newStack.setValue(name, value),为什么在OgnlValueStack设置呢?很奇怪!继续看
3、OgnlValueStack类setValue()代码:
1
2
3
4
|
public void setValue(String expr, Object value) { setValue(expr, value, devMode); } |
注释:很简单,继续看。
4、setValue()代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
|
public void setValue(String expr, Object value, boolean throwExceptionOnFailure) { Map<String, Object> context = getContext(); try { context.put(XWorkConverter.CONVERSION_PROPERTY_FULLNAME, expr); context.put(REPORT_ERRORS_ON_NO_PROP, (throwExceptionOnFailure) ? Boolean.TRUE : Boolean.FALSE); ognlUtil.setValue(expr, context, root, value); } catch (OgnlException e) { if (throwExceptionOnFailure) { e.printStackTrace(System.out); System.out.println( "expr: " + expr + " val: " + value + " context: " + context + " root:" + root + " value: " + value); String msg = "Error setting expression '" + expr + "' with value '" + value + "'" ; throw new XWorkException(msg, e); } else { if (LOG.isWarnEnabled()) { LOG.warn( "Error setting value" , e); } } } catch (RuntimeException re) { //XW-281 if (throwExceptionOnFailure) { StringBuilder msg = new StringBuilder(); msg.append( "Error setting expression '" ); msg.append(expr); msg.append( "' with value " ); if (value instanceof Object[]) { Object[] valueArray = (Object[]) value; msg.append( "[" ); for ( int index = 0 ; index < valueArray.length; index++) { msg.append( "'" ); msg.append(valueArray[index]); msg.append( "'" ); if (index < (valueArray.length + 1 )) msg.append( ", " ); } msg.append( "]" ); } else { msg.append( "'" ); msg.append(value); msg.append( "'" ); } throw new XWorkException(msg.toString(), re); } else { if (LOG.isWarnEnabled()) { LOG.warn( "Error setting value" , re); } } } finally { ReflectionContextState.clear(context); context.remove(XWorkConverter.CONVERSION_PROPERTY_FULLNAME); context.remove(REPORT_ERRORS_ON_NO_PROP); } } |
注释:到这里OgnlUtil.setValue(expr, context, this.root, value),在继续就是ognl框架执行的代码了,这里已经准备了ognl的三要素:expr表达式,context上下文,this.root 操作对象。但是这里为什么是root,为什么不是直接传递action对象呢?请继续看:
OgnlValueStack类中重要部分代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
public class OgnlValueStack implements Serializable, ValueStack, ClearableValueStack, MemberAccessValueStack { CompoundRoot root; transient Map<String, Object> context; Map<Object, Object> overrides; private static CompoundRootAccessor accessor; /* */ public OgnlValueStack(ValueStack vs) { /* 104 */ setRoot( new CompoundRoot(vs.getRoot())); /* */ } public Map getContext() /* */ { /* 126 */ return this .context; /* */ } public CompoundRoot getRoot() /* */ { /* 159 */ return this .root; /* */ } |
注释:(1)OgnlValueStack中变量context就是上面解释的OgnlContext对象。
(2)ValueStack中的root对象是CompoundRoot,CompoundRoot继承了ArraryList,提供了额外的方法:push()和pop()方法,用来对root对象中所包含的数据进行存取!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
public class CompoundRoot extends ArrayList { public CompoundRoot() { } public CompoundRoot(List list) { super (list); } public CompoundRoot cutStack( int index) { return new CompoundRoot(subList(index, size())); } public Object peek() { return get( 0 ); } public Object pop() { return remove( 0 ); } public void push(Object o) { add( 0 , o); } } |
正是通过这两个方法,CompoundRoot变成了一个栈结构!压栈操作,将导致对象被放到CompoundRoot的第0个元素上(第0个元素是栈顶),其它对象被依次往后移动;出栈操作,将导致CompoundRoot的第0个元素被移除(即栈顶元素被弹出),其它对象被依次往前移动!
OGNL不支持多个root对象,而struts2能够支持多个root对象,它对OGNL做了扩展。
如果某个OGNL表达式被传递给ValueStack(即调用ValueStack的setValue或findValue方法),而表达式中包含有对root对象的访问操作,ValueStack将依次从栈顶往栈底搜索CompoundRoot对象中所包含的对象,看哪个对象具有相应的属性,找到之后,立刻返回。
在Struts2中,一个请求在最终到达Action的方法之前,Action对象本身会被压入ValueStack(实际上就是放到ValueStack的CompoundRoot中),所以Action对象是CompoundRoot中的一个元素。
(3)CompoundRoot保存了action对象,那什么时候取出来执行呢?CompoundRootAccessor就派上用场了。当问某个属性时,CompoundRootAccessor对象实例会负责在CompoundRoot对象中找到包含我们指定属性的对象。简单的看一下CompoundRootAccessor类中的setProperty()方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
|
public void setProperty(Map context, Object target, Object name, Object value) throws OgnlException { CompoundRoot root = (CompoundRoot) target; OgnlContext ognlContext = (OgnlContext) context; for (Object o : root) { if (o == null ) { continue ; } try { if (OgnlRuntime.hasSetProperty(ognlContext, o, name)) { OgnlRuntime.setProperty(ognlContext, o, name, value); return ; } else if (o instanceof Map) { Map<Object, Object> map = (Map) o; map.put(name, value); return ; } // } catch (OgnlException e) { // if (e.getReason() != null) { // final String msg = "Caught an Ognl exception while setting property " + name; // log.error(msg, e); // throw new RuntimeException(msg, e.getReason()); // } } catch (IntrospectionException e) { // this is OK if this happens, we'll just keep trying the next } } Boolean reportError = (Boolean) context.get(ValueStack.REPORT_ERRORS_ON_NO_PROP); final String msg = "No object in the CompoundRoot has a publicly accessible property named '" + name + "' (no setter could be found)." ; if ((reportError != null ) && (reportError.booleanValue())) { throw new XWorkException(msg); } else { if (devMode) { LOG.warn(msg); } } } |
首先会把target转换成CompoundRoot对象。
把context转换成OgnlContext对象。
遍历 类型为CompoundRoot的root 对象,上面解释道CompoundRoot保存里action对象,所以获得action对象,进行属性值设置,OgnlRuntime.setProperty(ognlContext, o, name, value)。
到这里整体分析完成了。
http://my.oschina.net/winHerson/blog/110152