当前位置: 代码迷 >> J2EE >> Method类和cglib有鲜为人知的一腿?该如何解决
  详细解决方案

Method类和cglib有鲜为人知的一腿?该如何解决

热度:51   发布时间:2016-04-22 02:14:05.0
Method类和cglib有鲜为人知的一腿?
请看我另一篇帖子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会比较好。
  相关解决方案