请看我另一篇帖子http://topic.csdn.net/u/20100531/00/0fb8eeb7-e193-4e6f-9399-ef2aa0742d6b.html?300891006
经过我长达半天的追踪代码,发现了问题的所在,顺便给出这个帖子的解决方法:
问题就出在struts2中的chain拦截器中。当页面中使用了struts2标签中的<s:action>标签,或者其他显示返回chain结果时,在chain拦截器中,边会对一个上一个action的属性进行copy,而copy的实现是调用com.opensymphony.xwork2.ognl.OgnlUtil 类中的copy方法完成的,最终问题就是在这个方法中,请看代码:
- Java code
public void copy(Object from, Object to, Map<String, Object> context, Collection<String> exclusions, Collection<String> inclusions) { if (from == null || to == null) { LOG.warn("Attempting to copy from or to a null source. This is illegal and is bein skipped. This may be due to an error in an OGNL expression, action chaining, or some other event."); return; } TypeConverter conv = getTypeConverterFromContext(context); Map contextFrom = Ognl.createDefaultContext(from); Ognl.setTypeConverter(contextFrom, conv); Map contextTo = Ognl.createDefaultContext(to); Ognl.setTypeConverter(contextTo, conv); PropertyDescriptor[] fromPds; PropertyDescriptor[] toPds; try { fromPds = getPropertyDescriptors(from); toPds = getPropertyDescriptors(to); } catch (IntrospectionException e) { LOG.error("An error occured", e); return; } Map<String, PropertyDescriptor> toPdHash = new HashMap<String, PropertyDescriptor>(); for (PropertyDescriptor toPd : toPds) { toPdHash.put(toPd.getName(), toPd); } for (PropertyDescriptor fromPd : fromPds) { //修改部分 begin if("targetSource".equals(fromPd.getName()) || "callback".equals(fromPd.getName()) || "callbacks".equals(fromPd.getName())){ continue; } //修改部分 end if (fromPd.getReadMethod() != null) { boolean copy = true; if (exclusions != null && exclusions.contains(fromPd.getName())) { copy = false; } else if (inclusions != null && !inclusions.contains(fromPd.getName())) { copy = false; } if (copy == true) { PropertyDescriptor toPd = toPdHash.get(fromPd.getName()); if ((toPd != null) && (toPd.getWriteMethod() != null)) { try { Object expr = compile(fromPd.getName()); Object value = Ognl.getValue(expr, contextFrom, from); Ognl.setValue(expr, contextTo, to, value); } catch (OgnlException e) { // ignore, this is OK } } } } } }
将此类的方法修改如上,便可以解决我上个帖子出现的问题了。
现在说一下一个新的问题,望有牛人解答。
罗嗦说一下错误出现的稍微深入点的原因。当处理s:action标签时,在调用此copy()方法时,action是通过cglib动态生成的类,除了action原本的属性,cglib类还给这个action加上了几个属性,至于何用,我却也不知。这几个属性有targetSource,callback,callbacks等等。上面修改了的copy方法并不对这些属性进行复制,从而后面的action的这些属性不会给前面的action这些属性覆盖。而我继续追踪下去,直道调用Method.invoke()之前都不曾修改这些属性。
这意味着什么?
我个人猜测就是这些cglib附加上的属性,是Method.invoke中会用到的。可惜Method方法暂且能用反编译器反编译出来,然而里面调用到一个sun.reflect.MethodAccessor类时,却是功力不足,找不下去了。
据我了解,java包的Method等反射机制相关的sun都没有放出源码,而这些实现都是虚拟机来负责的(不知有无了解错),所以请对虚拟机和cglib两者熟悉的高人前来指点指点。
------解决方案--------------------
呵呵 很多框架 你不了解他的底层实现代码,很难用好,至于虚拟机和cglib的底层我还没研究,所以解答不了你,所以楼主加油。
------解决方案--------------------
cglib多用来搞定aop的功能。
比如批量拦截记录日志,声明式事务统一管理,权限拦截。
你可以去网上搜索reflect,proxy。要是能学学aop就更容易懂了。
BTW。用cglib搞了action,说明你把action定义到spring中,还加上了一层代理,个人觉得,还是不要让spring这样处理action比较好。因为每次action都需要新生成intance,你每次都加代理比较浪费,而且我们又不需要在action层处理事务,所以直接返还简单的pojo会比较好。