• 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的解析和验证上。



  • 相关阅读:
    git操作详解
    藏医诊疗管理系统
    广告的转化率预估
    python字符串及其内置函数详解
    python数据类型和运算符及运算符的优先级
    lunix常用命令
    返回结果的HTTP状态码
    简单的http协议
    git 上传项目到分支
    安装及使用webpack
  • 原文地址:https://www.cnblogs.com/Frank-Hao/p/5839140.html
Copyright © 2020-2023  润新知