BeanUtils.getProperty性能分析

接上文Java各類反射性能對比html

 

BeanUtils.getProperty的原理其實如下方法相似,但稍有不一樣java

 

  1. //代碼片斷4.1數組

  2.        PropertyDescriptor descriptor=null;緩存

  3.        BeanInfo beanInfo =Introspector.getBeanInfo(SimpleBean.class);
  4.        PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
  5.        for(PropertyDescriptor propertyDescriptor : propertyDescriptors){
  6.            if(propertyDescriptor.getName().equals("name")){
  7.                descriptor=propertyDescriptor;
  8.                break;
  9.            }
  10.        }
  11.        for(long i =0; i < times; i++){
  12.            descriptor.getReadMethod().invoke(bean);
  13.        }

 

先獲取BeanInfo,而後獲取全部PropertyDescriptors, 經過與想要獲取的屬性名對比,好比「name」,來獲取對應的propertyDescriptor,最後循環getReadMethod和invoke。性能

上面的測試消耗了大概2800ms( 由於只緩存了對應的PrepertyDescriptor,而不是對應的method ),BeanUtils.getProperty性能仍只有其1/7測試

最開始是懷疑BeanUtils.getProperty沒有對得到的PropertyDescriptor進行緩存,每次都從新查找對一個你的PropertyDescriptor,經過閱讀源碼,發現其經過一個與當前classloader綁定的ContextClassLoaderLocal實例來緩存匹配到的property,屬性valueByClassLoader就是用來保存的。this

private Map valueByClassLoader = new WeakHashMap();spa

這樣性能應該和上面的同樣纔對。3d

 

經過JProfiler分析調用過程,code

獲取PropertyDescriptor[]的調用消耗了2.9%的時間

  1.    publicPropertyDescriptor[] getPropertyDescriptors(Object bean){
  2.        if(bean ==null){
  3.            thrownewIllegalArgumentException("No bean specified");
  4.        }
  5.        return(getPropertyDescriptors(bean.getClass()));
  6.    }

獲取property的readMethod消耗了6.4%的時間

  1.    Method getReadMethod(Class clazz,PropertyDescriptor descriptor){
  2.        return(MethodUtils.getAccessibleMethod(clazz, descriptor.getReadMethod()));
  3.    }

而真正的method調用只消耗了1.6%的時間

  1. privateObject invokeMethod(
  2.                        Method method,
  3.                        Object bean,
  4.                        Object[] values)
  5.                            throws
  6.                                IllegalAccessException,
  7.                                InvocationTargetException{
  8.        if(bean ==null){
  9.            thrownewIllegalArgumentException("No bean specified "+
  10.                "- this should have been checked before reaching this method");
  11.        }
  12.        try{
  13.            
  14.            return method.invoke(bean, values);
  15.        
  16.        }catch(NullPointerException cause){
  17.              ....省略
  18. }

 

這些和反射有關的調用其實都沒有花太多時間,3000ms×(1.6%+6.4%)=2400ms,和代碼片斷4.1中的2800ms基本相同.

 

請看如下的方法調用時間:

這些方法佔了整個調用過程的54%的時間,這些是爲了使BeanUtils.getProperty不單單可以獲取bean的一級屬性,還可以判斷咱們所傳入的屬性是不是嵌套屬性,是不是從數組取值或者是map中取值,須要對傳入的屬性名不斷的解析,調用String.length()和String.charAt()兩個方法進行循環判斷。

 

感受大部分狀況下,咱們都只是解析一級屬性,BeanUtils中提供了一個方法,getSimpleProperty,測試的時間並無比getProperty快多少,1億次調用時間爲15299ms,主要時間和上面同樣花在了傳入的property name的解析和驗證上。

相關文章
相關標籤/搜索