刨根問底-struts和ognl密切分析

前面的2篇文章已經詳細的分析了ognl獲取數據的過程和設置數據的過程。其中最重要的點是ognl的三要素: java

(1)表達式(Expression)表達式是整個OGNL的核心,全部的OGNL操做都是針對表達式的解析後進行的。簡介的歸納「幹什麼」 mysql

(2)根對象(Root Object) 根對象能夠理解爲OGNL的操做對象簡介的歸納「對誰幹」或者「對誰操做」 web

(3)上下文環境(Context) OGNL的內部,全部的操做都會在一個特定的環境中運行,簡介的歸納「在哪幹」或者「在哪操做」 sql

若是明白了ognl的三要素,下面就好理解了。 express

刨根問底-struts-serviceAction()建立並執行action》中分析了執行action方法以前,循環執行攔截器,其中ParametersInterceptor攔截器主要工做:把jsp中傳來的數值賦值到action類中的屬性。如今就看看ParametersInterceptor類doIntercept()方法 apache

一、ParametersInterceptor類doIntercept()代碼: bootstrap

@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都爲空。 api

(2)判斷action是否屬於NoParameters接口,若是是什麼不處理 tomcat

(3)ActionContext ac = invocation.getInvocationContext(),獲取上下文對象ActionContext ,做爲struts2執行Action時的上下文,存儲了action在執行時須要用到的對象。如咱們須要關注的ServletContext,Session, HttpServletRequest ,parameters等。 session

 ActionContext類中有Map context全局變量,把全部的數據都保存到其中。

如今貼出context中的值:

{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設置參數

二、setParameters()代碼:

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設置呢?很奇怪!繼續看

三、OgnlValueStack類setValue()代碼:

public void setValue(String expr, Object value)
 {
   setValue(expr, value, devMode);
  }
註釋:很簡單,繼續看。

四、setValue()代碼:

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類中重要部分代碼

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對象中所包含的數據進行存取!

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()方法:

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)。

到這裏總體分析完成了。

相關文章
相關標籤/搜索