BeanUtils.getProperty性能分析


接上文Java各種反射性能對比

 

BeanUtils.getProperty的原理其實以下方法類似,但稍有不同

 

  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就是用來保存的。

private Map valueByClassLoader = new WeakHashMap();

這樣性能應該和上面的一樣才對。

 

通過JProfiler分析調用過程,

獲取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的解析和驗證上。

 




免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM