标签:
接上文Java各种反射性能对比
BeanUtils.getProperty的原理其实以下方法类似,但稍有不同
//代码片段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就是用来保存的。
private Map valueByClassLoader = new WeakHashMap();
这样性能应该和上面的一样才对。
通过JProfiler分析调用过程,

获取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的解析和验证上。
标签:
原文地址:http://www.cnblogs.com/Frank-Hao/p/5839140.html