接上文Java各類反射性能對比html
BeanUtils.getProperty的原理其實如下方法相似,但稍有不一樣java
//代碼片斷4.1數組
PropertyDescriptor descriptor=null;
緩存
BeanInfo beanInfo =Introspector.getBeanInfo(SimpleBean.class);
PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
for(PropertyDescriptor propertyDescriptor : propertyDescriptors){
if(propertyDescriptor.getName().equals("name")){
descriptor=propertyDescriptor;
break;
}
}
for(long i =0; i < times; i++){
descriptor.getReadMethod().invoke(bean);
}
先獲取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%的時間
publicPropertyDescriptor[] getPropertyDescriptors(Object bean){
if(bean ==null){
thrownewIllegalArgumentException("No bean specified");
}
return(getPropertyDescriptors(bean.getClass()));
}
獲取property的readMethod消耗了6.4%的時間
Method getReadMethod(Class clazz,PropertyDescriptor descriptor){
return(MethodUtils.getAccessibleMethod(clazz, descriptor.getReadMethod()));
}
而真正的method調用只消耗了1.6%的時間
privateObject invokeMethod(
Method method,
Object bean,
Object[] values)
throws
IllegalAccessException,
InvocationTargetException{
if(bean ==null){
thrownewIllegalArgumentException("No bean specified "+
"- this should have been checked before reaching this method");
}
try{
return method.invoke(bean, values);
}catch(NullPointerException cause){
....省略
}
這些和反射有關的調用其實都沒有花太多時間,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的解析和驗證上。