转:慎用Webwork的getText,使用不当效率可能会很低

很容易找到getText实际的操作类是LocalizedTextUtil,方法public static String findText(Class aClass, String aTextName, Locale locale, String defaultMessage, Object[] args, OgnlValueStack valueStack);

java doc 如下

Finds a localized text message for the given key, aTextName. Both the key and the message itself is evaluated as required. The following algorithm is used to find the requested message:

 

  1. Look for message in aClass' class hierarchy.
    1. Look for the message in a resource bundle for aClass
    2. If not found, look for the message in a resource bundle for any implemented interface
    3. If not found, traverse up the Class' hierarchy and repeat from the first sub-step
  2. If not found and aClass is a ModelDriven Action, then look for message in the model's class hierarchy (repeat sub-steps listed above).
  3. If not found, look for message in child property. This is determined by evaluating the message key as an OGNL expression. For example, if the key is user.address.state, then it will attempt to see if "user" can be resolved into an object. If so, repeat the entire process fromthe beginning with the object's class as aClass and "address.state" as the message key.
  4. If not found, look for the message in aClass' package hierarchy.
  5. If still not found, look for the message in the default resource bundles.
  6. Return defaultMessage

主要就是查找resource bundle,下面说明一下
1. 先查找该class(一般我们是在action调用,就是该action对应的class了)对应的properties文件,找不到再去找对应的接口,找不到再去从该class的继承树上去重复前面的步骤。
2. 如果是ModelDriver,以上找不到再以model的class去重复1的步骤
3.继续找,如果key是符合ognl表达式还以ognl表达式去解析类,如果能找到类,还以以上的步骤去查找
4. 还找不到,就从根据package以及package的继承树去找,这还包括了该class的继承树所有的class的package树(这一步存在了太多的重复查找工作,因为很多package都是相同的)
5 使用默认的resource bundle

java.util.ResourceBundle虽然有cache,但是ww为了减少调用getResourceBundle方法,也维护了一个miss的hashset,找不到的bundle name就丢进去,那么每一次查找都同步了这个miss,如果很多次查找,开销也是很大的。

我就举一个例子,就说第四步查找package树好了

        // nothing still? alright, search the package hierarchy now
        for (Class clazz = aClass;
             (clazz 
!= null&& !clazz.equals(Object.class);
             clazz 
= clazz.getSuperclass()) {

            String basePackageName 
= clazz.getName();
            
while (basePackageName.lastIndexOf('.'!= -1) {
                basePackageName 
= basePackageName.substring(0, basePackageName.lastIndexOf('.'));
                String packageName 
= basePackageName + ".package";
                msg 
= getMessage(packageName, locale, aTextName, valueStack, args);

                
if (msg != null) {
                    
return msg;
                }

                
if (indexedTextName != null) {
                    msg 
= getMessage(packageName, locale, indexedTextName, valueStack, args);

                    
if (msg != null) {
                        
return msg;
                    }
                }
            }
        }

假设你的action继承树是这样
com.bba96.core.webwork.actions.DefaultActionSupport
com.xxxx.web.actions.XXXActionSupport
com.xxxx.web.user.actions.UserAction
com.xxxx.web.user.ViewUserAction
且不说ww没有判断是否是com.opensymphony.xwork.ActionSupport或者ww的接口就停止,光是自己的继承树,就是4+3+3+3=13次,再加上往上的继承树以及对应的接口,com.opensymphony.xwork.ActionSupport以及Action, Validateable, ValidationAware, TextProvider, LocaleProvider, Serializable, ContinuableObject的接口,查找次数超过30次甚至更多,这里的每一次都有一个同步miss的过程,开销相当大。

如果你的key所在的resource bundle没有对应到合适的class或package时,例如说放在了default bundle中,ww会浪费很多时间。这种情况下,我在没有并发的时候测了一下,一次getText大概耗时40ms左右

所以在实际应用我们应该避免这种情况出现,要不让resource bundle一一对应class,要不就自己实现一个简单的getText,其实要是ww的ActionSupport的textProvider允许改变就最好了。

posted @ 2008-05-23 14:10  harry.guo  阅读(605)  评论(0编辑  收藏  举报