OgnlValueStack的结构和几个方法分析
2016-09-26 10:30
417 查看
首先,我们来看一下在那里创建了OgnlValueStack。在Struts2过滤器的doFilter方法中 prepare.createActionContext(request, response)这一条代码中,创建了actioncontext,并且创建了valuestack。下面我们来看看。
走到createValueStack()那一条代码。
这里在valuestack的context中放入了ActionContext.CONTAINER
这里看到将prov放到了valuestack的根栈中,而这个prov就是TextProvider
这里为valuestack设置一些属性值,比如根栈和context,这里我们去看看如何创建context。createDefaultContext这个方法就是创建了context。
继续去看一下addDefaultContext方法
这里返回一个result,并且将root设置给result,而result对象是一个OgnlContext,实现了Map接口,而这个root是设置给result对象的_root对象,下面继续看一下这个方法
下面我们可以知道valuestack的结构,引用别人的一张图,在此感谢图的作者。
下面稍微看一下OgnlValueStack几个方法
1、setValue(expr,value)方法
看一下trySetValue方法
继续看ognlUtil.setValue方法
这里去看一下compileAndExecute()方法
这里发现是将expr转化成tree对象了
下面继续回到ognlUtil.setValue方法,找到这一条代码 Ognl.setValue()方法,去看一下啊
继续 n.setValue(ognlContext, root, value)
这里去看一下evaluateSetValueBody()方法
看setValueBody方法
在这个类没有实现,在其他子类中实现,也就是说转化的tree其实不是simplenNode对象,而是跟对象的子类。这里大体就是如果不带#就放到valuestack的根栈中,如果带#就放到context中。
2、set(key,value)
看一下retrieveSetMap()f方法
这里的意思就是先在根栈中寻找栈顶是否是map类型的对象,如果是则使用,如果不是就新创建一个map,然后将新建好的map放入栈顶。然后看到一开始的set方法内,将key,value设置给map。
3、findValue,findString方法
这里是全都调用findValue方法
发现这几个findValue方法都调用了tryFindValueWhenExpressionIsNotNull()。走进去看一下
看tryFindValue()方法
在这里看到看到getValue和findInContext这两个方法
可以看出先是到valuestack的根栈中寻找,然后到context中寻找,到此源码解读完毕
public ActionContext createActionContext(HttpServletRequest request, HttpServletResponse response) { ActionContext ctx; Integer counter = 1; Integer oldCounter = (Integer) request.getAttribute(CLEANUP_RECURSION_COUNTER); if (oldCounter != null) { counter = oldCounter + 1; } ActionContext oldContext = ActionContext.getContext(); if (oldContext != null) { // detected existing context, so we are probably in a forward ctx = new ActionContext(new HashMap<String, Object>(oldContext.getContextMap())); } else { ValueStack stack = dispatcher.getContainer().getInstance(ValueStackFactory.class).createValueStack(); stack.getContext().putAll(dispatcher.createContextMap(request, response, null, servletContext)); ctx = new ActionContext(stack.getContext()); } request.setAttribute(CLEANUP_RECURSION_COUNTER, counter); ActionContext.setContext(ctx); return ctx; }
走到createValueStack()那一条代码。
public ValueStack createValueStack() { ValueStack stack = new OgnlValueStack(xworkConverter, compoundRootAccessor, textProvider, allowStaticMethodAccess); container.inject(stack); stack.getContext().put(ActionContext.CONTAINER, container); return stack; }
这里在valuestack的context中放入了ActionContext.CONTAINER
protected OgnlValueStack(XWorkConverter xworkConverter, CompoundRootAccessor accessor, TextProvider prov, boolean allowStaticAccess) { setRoot(xworkConverter, accessor, new CompoundRoot(), allowStaticAccess); push(prov); }
这里看到将prov放到了valuestack的根栈中,而这个prov就是TextProvider
protected void setRoot(XWorkConverter xworkConverter, CompoundRootAccessor accessor, CompoundRoot compoundRoot, boolean allowStaticMethodAccess) { this.root = compoundRoot; this.securityMemberAccess = new SecurityMemberAccess(allowStaticMethodAccess); this.context = Ognl.createDefaultContext(this.root, accessor, new OgnlTypeConverterWrapper(xworkConverter), securityMemberAccess); context.put(VALUE_STACK, this); Ognl.setClassResolver(context, accessor); ((OgnlContext) context).setTraceEvaluations(false); ((OgnlContext) context).setKeepLastEvaluation(false); }
这里为valuestack设置一些属性值,比如根栈和context,这里我们去看看如何创建context。createDefaultContext这个方法就是创建了context。
public static Map createDefaultContext(Object root, ClassResolver classResolver, TypeConverter converter, MemberAccess memberAccess) { return addDefaultContext(root, classResolver, converter, memberAccess, new OgnlContext()); }
继续去看一下addDefaultContext方法
public static Map addDefaultContext(Object root, ClassResolver classResolver, TypeConverter converter, MemberAccess memberAccess, Map context) { OgnlContext result; if (!(context instanceof OgnlContext)) { result = new OgnlContext(); result.setValues(context); } else { result = (OgnlContext) context; } if (classResolver != null) { result.setClassResolver(classResolver); } if (converter != null) { result.setTypeConverter(converter); } if (memberAccess != null) { result.setMemberAccess(memberAccess); } result.setRoot(root); return result; }
这里返回一个result,并且将root设置给result,而result对象是一个OgnlContext,实现了Map接口,而这个root是设置给result对象的_root对象,下面继续看一下这个方法
public void setRoot(Object value) { _root = value; _accessorStack.clear(); _typeStack.clear(); _currentObject = value; if (_currentObject != null) { setCurrentType(_currentObject.getClass()); } }
下面我们可以知道valuestack的结构,引用别人的一张图,在此感谢图的作者。
下面稍微看一下OgnlValueStack几个方法
1、setValue(expr,value)方法
public void setValue(String expr, Object value, boolean throwExceptionOnFailure) { Map<String, Object> context = getContext(); try { trySetValue(expr, value, throwExceptionOnFailure, context); } catch (OgnlException e) { handleOgnlException(expr, value, throwExceptionOnFailure, e); } catch (RuntimeException re) { //XW-281 handleRuntimeException(expr, value, throwExceptionOnFailure, re); } finally { cleanUpContext(context); } }
看一下trySetValue方法
private void trySetValue(String expr, Object value, boolean throwExceptionOnFailure, Map<String, Object> context) throws OgnlException { 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); }
继续看ognlUtil.setValue方法
public void setValue(final String name, final Map<String, Object> context, final Object root, final Object value) throws OgnlException { compileAndExecute(name, context, new OgnlTask<Void>() { public Void execute(Object tree) throws OgnlException { if (isEvalExpression(tree, context)) { throw new OgnlException("Eval expression/chained expressions cannot be used as parameter name"); } if (isArithmeticExpression(tree, context)) { throw new OgnlException("Arithmetic expressions cannot be used as parameter name"); } Ognl.setValue(tree, context, root, value); return null; } }); }
这里去看一下compileAndExecute()方法
private <T> Object compileAndExecute(String expression, Map<String, Object> context, OgnlTask<T> task) throws OgnlException { Object tree; if (enableExpressionCache) { tree = expressions.get(expression); if (tree == null) { tree = Ognl.parseExpression(expression); checkEnableEvalExpression(tree, context); } } else { tree = Ognl.parseExpression(expression); checkEnableEvalExpression(tree, context); } final T exec = task.execute(tree); // if cache is enabled and it's a valid expression, puts it in if(enableExpressionCache) { expressions.putIfAbsent(expression, tree); } return exec; }
这里发现是将expr转化成tree对象了
下面继续回到ognlUtil.setValue方法,找到这一条代码 Ognl.setValue()方法,去看一下啊
public static void setValue(Object tree, Map context, Object root, Object value) throws OgnlException { OgnlContext ognlContext = (OgnlContext) addDefaultContext(root, context); Node n = (Node) tree; if (n.getAccessor() != null) { n.getAccessor().set(ognlContext, root, value); return; } n.setValue(ognlContext, root, value); }
继续 n.setValue(ognlContext, root, value)
public final void setValue(OgnlContext context, Object target, Object value) throws OgnlException { if (context.getTraceEvaluations()) { EvaluationPool pool = OgnlRuntime.getEvaluationPool(); Throwable evalException = null; Evaluation evaluation = pool.create(this, target, true); context.pushEvaluation(evaluation); try { evaluateSetValueBody(context, target, value); } catch (OgnlException ex) { evalException = ex; ex.setEvaluation(evaluation); throw ex; } catch (RuntimeException ex) { evalException = ex; throw ex; } finally { Evaluation eval = context.popEvaluation(); if (evalException != null) { eval.setException(evalException); } if ((evalException == null) && (context.getRootEvaluation() == null) && !context.getKeepLastEvaluation()) { pool.recycleAll(eval); } } } else { evaluateSetValueBody(context, target, value); } }
这里去看一下evaluateSetValueBody()方法
protected void evaluateSetValueBody(OgnlContext context, Object target, Object value) throws OgnlException { context.setCurrentObject(target); context.setCurrentNode(this); setValueBody(context, target, value); }
看setValueBody方法
protected void setValueBody(OgnlContext context, Object target, Object value) throws OgnlException { throw new InappropriateExpressionException(this); }
在这个类没有实现,在其他子类中实现,也就是说转化的tree其实不是simplenNode对象,而是跟对象的子类。这里大体就是如果不带#就放到valuestack的根栈中,如果带#就放到context中。
2、set(key,value)
public void set(String key, Object o) { //set basically is backed by a Map pushed on the stack with a key being put on the map and the Object being the value Map setMap = retrieveSetMap(); setMap.put(key, o); }
看一下retrieveSetMap()f方法
private Map retrieveSetMap() { Map setMap; Object topObj = peek(); if (shouldUseOldMap(topObj)) { setMap = (Map) topObj; } else { setMap = new HashMap(); setMap.put(MAP_IDENTIFIER_KEY, ""); push(setMap); } return setMap; }
这里的意思就是先在根栈中寻找栈顶是否是map类型的对象,如果是则使用,如果不是就新创建一个map,然后将新建好的map放入栈顶。然后看到一开始的set方法内,将key,value设置给map。
3、findValue,findString方法
public String findString(String expr) { return (String) findValue(expr, String.class); } public String findString(String expr, boolean throwExceptionOnFailure) { return (String) findValue(expr, String.class, throwExceptionOnFailure); }
这里是全都调用findValue方法
public Object findValue(String expr, boolean throwExceptionOnFailure) { try { setupExceptionOnFailure(throwExceptionOnFailure); return tryFindValueWhenExpressionIsNotNull(expr); } catch (OgnlException e) { return handleOgnlException(expr, throwExceptionOnFailure, e); } catch (Exception e) { return handleOtherException(expr, throwExceptionOnFailure, e); } finally { ReflectionContextState.clear(context); } }
public Object findValue(String expr) { return findValue(expr, false); }
public Object findValue(String expr, Class asType, boolean throwExceptionOnFailure) { try { setupExceptionOnFailure(throwExceptionOnFailure); return tryFindValueWhenExpressionIsNotNull(expr, asType); } catch (OgnlException e) { final Object value = handleOgnlException(expr, throwExceptionOnFailure, e); return converter.convertValue(getContext(), value, asType); } catch (Exception e) { final Object value = handleOtherException(expr, throwExceptionOnFailure, e); return converter.convertValue(getContext(), value, asType); } finally { ReflectionContextState.clear(context); } }
发现这几个findValue方法都调用了tryFindValueWhenExpressionIsNotNull()。走进去看一下
private Object tryFindValueWhenExpressionIsNotNull(String expr, Class asType) throws OgnlException { if (expr == null) { return null; } return tryFindValue(expr, asType); }
看tryFindValue()方法
private Object tryFindValue(String expr, Class asType) throws OgnlException { Object value = null; try { expr = lookupForOverrides(expr); value = getValue(expr, asType); if (value == null) { value = findInContext(expr); return converter.convertValue(getContext(), value, asType); } } finally { context.remove(THROW_EXCEPTION_ON_FAILURE); } return value; }
在这里看到看到getValue和findInContext这两个方法
private Object getValue(String expr, Class asType) throws OgnlException { return ognlUtil.getValue(expr, context, root, asType); } private Object findInContext(String name) { return getContext().get(name); }
可以看出先是到valuestack的根栈中寻找,然后到context中寻找,到此源码解读完毕
相关文章推荐
- 几个功能强大的分析SQL Server数据库结构的存储过程
- 网站广告位难卖的几个原因分析与解决方法
- Linux内核--网络协议栈深入分析(一)--与sk_buff有关的几个重要的数据结构
- XBMC源代码分析 1:整体结构以及编译方法
- XBMC源代码分析 1:整体结构以及编译方法
- MIDI文件结构分析及生成方法
- 几个复制表结构和表数据的方法
- midi文件结构分析及生成方法_移动短信技术
- MIDI文件结构分析及生成方法
- 模板方法模式分析、结构图和基本代码
- MIDI文件结构分析及生成方法
- 2011年上半年系统集成项目管理工程师考试试题结构分析暨后续复习方法浅谈
- 2011年5月 系统集成项目管理工程师试题结构分析暨后续复习方法浅谈
- Linux内核--网络协议栈深入分析(一)--与sk_buff有关的几个重要的数据结构
- 面向数据流的分析方法VS面向数据结构的分析方法
- MIDI文件结构分析及生成方法
- 求a^x展开的欧拉方法(基本分析结构)
- C#WinForm程序最小化后在托盘中隐藏方法以及几个关键点的简单分析
- jQuery1.9.1--结构及$方法的工作原理源码分析
- 通讯录结构体方法的实现 和VS中存在的一些问题的分析